package com.ssy.lingxi.order.serviceimpl.base;

import com.ssy.lingxi.common.constant.basic.FundModeEnum;
import com.ssy.lingxi.common.constant.basic.UserLoginSourceEnum;
import com.ssy.lingxi.common.constant.order.OrderPayChannelEnum;
import com.ssy.lingxi.common.constant.order.OrderPayTypeEnum;
import com.ssy.lingxi.common.constant.order.OrderPaymentParameterEnum;
import com.ssy.lingxi.common.constant.order.OrderPaymentSettlementStatusEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.model.constant.MemberRightSpendTypeEnum;
import com.ssy.lingxi.order.entity.OrderDO;
import com.ssy.lingxi.order.entity.OrderPaymentDO;
import com.ssy.lingxi.order.model.bo.*;
import com.ssy.lingxi.order.model.constant.*;
import com.ssy.lingxi.order.model.dto.*;
import com.ssy.lingxi.order.model.vo.basic.request.OrderPaymentVO;
import com.ssy.lingxi.order.model.vo.basic.response.OrderPayTypeDetailVO;
import com.ssy.lingxi.order.model.vo.buyer.response.BuyerOrderPayNodeQueryVO;
import com.ssy.lingxi.order.model.vo.buyer.response.BuyerOrderPaymentDetailVO;
import com.ssy.lingxi.order.model.vo.buyer.response.BuyerPayResultDetailVO;
import com.ssy.lingxi.order.model.vo.vendor.response.VendorOrderPaymentDetailVO;
import com.ssy.lingxi.order.repository.OrderPaymentRepository;
import com.ssy.lingxi.order.repository.OrderRepository;
import com.ssy.lingxi.order.service.base.*;
import com.ssy.lingxi.order.service.feign.IMemberFeignService;
import com.ssy.lingxi.order.service.feign.IPayFeignService;
import com.ssy.lingxi.order.service.feign.ISettleAccountFeignService;
import com.ssy.lingxi.order.utils.NumberUtil;
import com.ssy.lingxi.order.utils.OrderDateTimeUtil;
import com.ssy.lingxi.order.utils.OrderStringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 订单支付记录相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-07-20
 */
@Service
public class BaseOrderPaymentServiceImpl implements IBaseOrderPaymentService {
    private static final Logger logger = LoggerFactory.getLogger(BaseOrderPaymentServiceImpl.class);
    @Resource
    private OrderRepository orderRepository;

    @Resource
    private OrderPaymentRepository orderPaymentRepository;

    @Resource
    private IBaseOrderService baseOrderService;

    @Resource
    private IBaseOrderHistoryService baseOrderHistoryService;

    @Resource
    private IBaseOrderProcessService baseOrderProcessService;

    @Resource
    private IBaseOrderTaskService baseOrderTaskService;

    @Resource
    private IBaseOrderProductService baseOrderProductService;

    @Resource
    private IPayFeignService payFeignService;

    @Resource
    private IMemberFeignService memberFeignService;

    @Resource
    private ISettleAccountFeignService settleAccountFeignService;

    @Resource
    private IBaseCacheService baseCacheService;

    @Resource
    private IBaseOrderScheduleService baseOrderScheduleService;

    /**
     * 校验、保存订单支付记录，调用方要保存 OrderDO
     *
     * @param order 订单
     * @param payType 订单支付方式
     * @param payChannel 订单支付渠道
     * @param payNodes 交易流程中设置的支付环节
     * @return 资金归集模式
     */
    @Override
    public Wrapper<OrderPaymentCheckBO> checkOrderPayment(OrderDO order, Integer payType, Integer payChannel, List<PayNodeBO> payNodes) {
        //Step 1: 如果交易流程中的支付环节为空，表示不需要支付，返回
        if(CollectionUtils.isEmpty(payNodes) || payType.equals(OrderPayTypeEnum.DOES_NOT_NEED.getCode())) {
            order.setPayments(new HashSet<>());
            return Wrapper.success(new OrderPaymentCheckBO());
        }

        Integer fundMode;
        if(payType.equals(OrderPayTypeEnum.SETTLEMENT.getCode())) {
            Wrapper<OrderPayTypeDetailVO> settlementResult = settleAccountFeignService.findSettlementPaySetting(order);
            if(settlementResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(settlementResult.getCode(), settlementResult.getMessage());
            }

            if(Objects.isNull(settlementResult.getData()) || settlementResult.getData().getPayChannels().stream().noneMatch(channel -> channel.getPayChannel().equals(payChannel))) {
                return Wrapper.fail(ResponseCode.ORDER_SETTLEMENT_PAYMENT_SETTING_NOT_SET_YET);
            }

            fundMode = settlementResult.getData().getFundMode();
        } else {
            //Step 2: 查询平台后台 - 会员支付策略配置，获得资金归集模式，拼接结算支付查询
            List<PlatformPayTypeBO> platformPayTypes = baseOrderProcessService.findPlatformMemberPayment(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getVendorMemberId(), order.getVendorRoleId(), payChannel.equals(OrderPayTypeEnum.SETTLEMENT.getCode()));
            if(CollectionUtils.isEmpty(platformPayTypes)) {
                return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_NOT_SET_YET);
            }

            fundMode = platformPayTypes.stream().filter(platformPayType -> platformPayType.getPayType().equals(payType) && platformPayType.getChannels().stream().anyMatch(platformPayChannel -> platformPayChannel.getPayChannel().equals(payChannel))).map(PlatformPayTypeBO::getFundMode).findFirst().orElse(0);
            if(NumberUtil.isNullOrZero(fundMode)) {
                return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_MISMATCH);
            }
        }

        //Step 3: 计算每批次支付的金额
        Map<Integer, BigDecimal> batchAmount = averagePayNodeAmount(order.getTotalAmount(), payNodes);

        //Step 4: 生成支付记录
        List<OrderPaymentDO> orderPayments = payNodes.stream().map(payNode -> {
            OrderPaymentDO orderPayment = new OrderPaymentDO();
            orderPayment.setOrder(order);
            orderPayment.setPayTime(null);
            orderPayment.setConfirmTime(null);
            orderPayment.setSerialNo(payNode.getSerialNo());
            orderPayment.setBatchNo(payNode.getBatchNo());
            orderPayment.setPayType(payType);
            orderPayment.setPayChannel(payChannel);
            orderPayment.setFundMode(fundMode);
            orderPayment.setPayNode(payNode.getPayNode());
            orderPayment.setPayRate(payNode.getPayRate());
            BigDecimal payAmount = batchAmount.getOrDefault(payNode.getBatchNo(), BigDecimal.ZERO);
            orderPayment.setPayAmount(payAmount);
            //支付金额为0的，设置为完成状态
            if(payAmount.compareTo(BigDecimal.ZERO) == 0) {
                orderPayment.setPayTime(LocalDateTime.now());
                orderPayment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_PAY_SUCCESS.getCode());
                orderPayment.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_PAYMENT_CONFIRMED.getCode());
                orderPayment.setOuterStatus(OrderOuterStatusEnum.ACCOMPLISHED.getCode());
            } else {
                orderPayment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_TO_PAY.getCode());
                orderPayment.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_TO_CONFIRM_PAYMENT.getCode());
                orderPayment.setOuterStatus(OrderOuterStatusEnum.TO_PAY.getCode());
            }
            orderPayment.setSettlementStatus(OrderPaymentSettlementStatusEnum.NONE.getCode());
            orderPayment.setTradeNo("");
            orderPayment.setRefundNo("");
            orderPayment.setVouchers(new ArrayList<>());
            return orderPayment;
        }).collect(Collectors.toList());

        //Step 6: 保存
        orderPaymentRepository.saveAll(orderPayments);

        //Step 7: 设置关联，调用方保存OrderDO
        order.setPayments(new HashSet<>(orderPayments));

        //Step 8: 返回信息
        return Wrapper.success(new OrderPaymentCheckBO(fundMode, orderPayments.stream().anyMatch(payment -> payment.getPayRate().compareTo(BigDecimal.ONE) == 0)));
    }

    /**
     * 校验、保存（积分兑换）订单支付记录，调用方要保存 OrderDO
     *
     * @param order      订单
     * @param payType    订单支付方式
     * @param payChannel 订单支付渠道
     * @param payNodes   交易流程中设置的支付环节
     * @return 资金归集模式
     */
    @Override
    public Wrapper<Integer> checkPointsOrderPayment(OrderDO order, Integer payType, Integer payChannel, List<PayNodeBO> payNodes) {
        //Step 1: 如果交易流程中的支付环节为空，表示不需要支付，返回
        if(CollectionUtils.isEmpty(payNodes) || payType.equals(OrderPayTypeEnum.DOES_NOT_NEED.getCode())) {
            order.setPayments(new HashSet<>());
            return Wrapper.success(0);
        }

        //Step 2: 计算每批次支付的金额
        Map<Integer, BigDecimal> batchAmount = averagePayNodeAmount(order.getTotalAmount(), payNodes);

        //Step 3: 生成支付记录
        List<OrderPaymentDO> orderPayments = payNodes.stream().map(payNode -> {
            OrderPaymentDO orderPayment = new OrderPaymentDO();
            orderPayment.setOrder(order);
            orderPayment.setPayTime(null);
            orderPayment.setConfirmTime(null);
            orderPayment.setSerialNo(payNode.getSerialNo());
            orderPayment.setBatchNo(payNode.getBatchNo());
            orderPayment.setPayType(payType);
            orderPayment.setPayChannel(payChannel);
            //积分订单的资金归集模式暂时设置为“平台代收”，待支付时才根据接口参数进行修改
            orderPayment.setFundMode(FundModeEnum.PLATFORM_EXCHANGE.getCode());
            orderPayment.setPayNode(payNode.getPayNode());
            orderPayment.setPayRate(payNode.getPayRate());
            BigDecimal payAmount = batchAmount.getOrDefault(payNode.getBatchNo(), BigDecimal.ZERO);
            orderPayment.setPayAmount(payAmount);
            //支付金额为0的，设置为完成状态
            if(payAmount.compareTo(BigDecimal.ZERO) == 0) {
                orderPayment.setPayTime(LocalDateTime.now());
                orderPayment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_PAY_SUCCESS.getCode());
                orderPayment.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_PAYMENT_CONFIRMED.getCode());
                orderPayment.setOuterStatus(OrderOuterStatusEnum.ACCOMPLISHED.getCode());
            } else {
                orderPayment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_TO_PAY.getCode());
                orderPayment.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_TO_CONFIRM_PAYMENT.getCode());
                orderPayment.setOuterStatus(OrderOuterStatusEnum.TO_PAY.getCode());
            }
            orderPayment.setSettlementStatus(OrderPaymentSettlementStatusEnum.NONE.getCode());
            orderPayment.setTradeNo("");
            orderPayment.setRefundNo("");
            orderPayment.setVouchers(new ArrayList<>());
            return orderPayment;
        }).collect(Collectors.toList());

        //Step 4: 保存
        orderPaymentRepository.saveAll(orderPayments);

        //Step 5: 设置关联，调用方保存OrderDO
        order.setPayments(new HashSet<>(orderPayments));
        return Wrapper.success(null);
    }

    /**
     * 校验、保存B2B订单支付记录，调用方要保存OrderDO
     *
     * @param order        订单
     * @param payNodes     供应商交易流程设置中的支付环节
     * @param payments     接口参数
     * @param isCreate     是否是新增，true-新增，false-修改
     * @return 校验结果
     */
    @Override
    public Wrapper<Void> checkOrderCreatePayment(OrderDO order, List<PayNodeBO> payNodes, List<OrderPaymentVO> payments, boolean isCreate) {
        //Step 1: 如果不需要支付，返回
        if(CollectionUtils.isEmpty(payNodes)) {
            orderPaymentRepository.deleteByOrder(order);
            order.setPayments(new HashSet<>());
            return Wrapper.success();
        }

        //Step 2: 查询平台后台 - 会员支付策略配置，获得资金归集模式，拼接结算支付方式查询
        List<PlatformPayTypeBO> platformPayTypes = baseOrderProcessService.findPlatformMemberPayment(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getVendorMemberId(), order.getVendorRoleId(), payments.stream().allMatch(p -> p.getPayType().equals(OrderPayTypeEnum.SETTLEMENT.getCode())));
        if(CollectionUtils.isEmpty(platformPayTypes)) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_NOT_SET_YET);
        }

        //Step 3: 判断支付记录的次数是否与供应商交易流程规则配置中的次数相匹配，忽略支付比例配置为0的支付环节
        if(CollectionUtils.isEmpty(payments) || payments.size() != payNodes.stream().filter(payNode -> payNode.getPayRate().compareTo(BigDecimal.ZERO) > 0).count() || payments.stream().anyMatch(payment -> payNodes.stream().noneMatch(payNode -> payNode.getBatchNo().equals(payment.getBatchNo())))) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENTS_MISMATCH_WITH_TRADE_PROCESS);
        }

        //Step 4: 判断支付方式与支付渠道，是否在会员支付策略中
        if(payments.stream().anyMatch(payment -> platformPayTypes.stream().noneMatch(platformPayType -> platformPayType.getPayType().equals(payment.getPayType()) || platformPayType.getChannels().stream().anyMatch(payChannel -> payChannel.getPayChannel().equals(payment.getPayChannel()))))) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENTS_MISMATCH_WITH_PLATFORM_PAYMENTS);
        }

        //Step 5: 计算每批次支付的金额
        Map<Integer, BigDecimal> batchAmount = averagePayNodeAmount(order.getTotalAmount(), payNodes);

        //Step 6: 生成支付记录（创建订单由于前端传递的是支付次数已经过滤掉了支付比例为0的，所以这里需要补齐）
        List<OrderPaymentDO> orderPayments = payNodes.stream().map(payNode -> {
            OrderPaymentVO paymentVO = payments.stream().filter(p -> p.getBatchNo().equals(payNode.getBatchNo())).findFirst().orElse(null);

            OrderPaymentDO orderPayment = new OrderPaymentDO();
            orderPayment.setOrder(order);
            orderPayment.setPayTime(null);
            orderPayment.setConfirmTime(null);
            orderPayment.setSerialNo(payNode.getSerialNo());
            orderPayment.setBatchNo(payNode.getBatchNo());
            orderPayment.setPayNode(payNode.getPayNode());
            orderPayment.setPayRate(payNode.getPayRate());

            if(paymentVO == null) {
                orderPayment.setPayType(OrderPayTypeEnum.DOES_NOT_NEED.getCode());
                orderPayment.setPayChannel(OrderPayTypeEnum.DOES_NOT_NEED.getCode());
                orderPayment.setFundMode(FundModeEnum.PLATFORM_EXCHANGE.getCode());
            } else {
                orderPayment.setPayType(paymentVO.getPayType());
                orderPayment.setPayChannel(paymentVO.getPayChannel());
                platformPayTypes.stream().filter(platformPayType -> platformPayType.getPayType().equals(paymentVO.getPayType()) && platformPayType.getChannels().stream().anyMatch(platformPayChannel -> platformPayChannel.getPayChannel().equals(paymentVO.getPayChannel()))).findFirst().ifPresent(platformPayType -> orderPayment.setFundMode(platformPayType.getFundMode()));
            }

            orderPayment.setPayAmount(batchAmount.getOrDefault(payNode.getBatchNo(), BigDecimal.ZERO));
            //支付金额为0的，设置为完成状态
            if(orderPayment.getPayAmount().compareTo(BigDecimal.ZERO) == 0) {
                orderPayment.setPayTime(LocalDateTime.now());
                orderPayment.setConfirmTime(LocalDateTime.now());
                orderPayment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_PAY_SUCCESS.getCode());
                orderPayment.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_PAYMENT_CONFIRMED.getCode());
                orderPayment.setOuterStatus(OrderOuterStatusEnum.ACCOMPLISHED.getCode());
            } else {
                orderPayment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_TO_PAY.getCode());
                orderPayment.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_TO_CONFIRM_PAYMENT.getCode());
                orderPayment.setOuterStatus(OrderOuterStatusEnum.TO_PAY.getCode());
            }
            orderPayment.setSettlementStatus(OrderPaymentSettlementStatusEnum.NONE.getCode());
            orderPayment.setTradeNo("");
            orderPayment.setRefundNo("");
            orderPayment.setVouchers(new ArrayList<>());
            return orderPayment;
        }).collect(Collectors.toList());

        //如果是修改，删除原有的
        if(!isCreate) {
            orderPaymentRepository.deleteByOrder(order);
        }

        //保存并设置关联
        orderPaymentRepository.saveAll(orderPayments);
        order.setPayments(new HashSet<>(orderPayments));

        return Wrapper.success();
    }

    /**
     * 修改新增订单支付记录
     *
     * @param order    订单
     * @param payments 接口参数
     * @return 校验结果
     */
    @Override
    public Wrapper<Void> updateOrderCreatePayment(OrderDO order, List<OrderPaymentVO> payments) {
        //Step 1: 查询平台后台 - 会员支付策略配置，获得资金归集模式
        List<PlatformPayTypeBO> platformPayTypes = baseOrderProcessService.findPlatformMemberPayment(order.getVendorMemberId(), order.getVendorRoleId());
        if(CollectionUtils.isEmpty(platformPayTypes)) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_SETTING_NOT_SET_YET);
        }

        //Step 2: 如果不需要支付，返回
        if(CollectionUtils.isEmpty(platformPayTypes)) {
            orderPaymentRepository.deleteByOrder(order);
            order.setPayments(new HashSet<>());
            return Wrapper.success();
        }

        //Step 3: 判断支付方式与支付渠道，是否在会员支付策略中
        if(CollectionUtils.isEmpty(payments) || payments.stream().anyMatch(payment -> platformPayTypes.stream().noneMatch(platformPayType -> platformPayType.getPayType().equals(payment.getPayType()) || platformPayType.getChannels().stream().anyMatch(payChannel -> payChannel.getPayChannel().equals(payment.getPayChannel()))))) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENTS_MISMATCH_WITH_PLATFORM_PAYMENTS);
        }

        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findByOrder(order);
        if(payments.stream().anyMatch(payment -> orderPayments.stream().noneMatch(p -> p.getBatchNo().equals(payment.getBatchNo())))) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_DOES_NOT_EXIST);
        }

        //Step 4: 修改支付方式、支付渠道、资金归集模式
        List<OrderPaymentDO> updatePayments = new ArrayList<>();
        for (OrderPaymentDO orderPayment : orderPayments) {
            OrderPaymentVO paymentVO = payments.stream().filter(p -> p.getBatchNo().equals(orderPayment.getBatchNo())).findFirst().orElse(null);
            if(paymentVO == null) {
                continue;
            }

            orderPayment.setPayType(paymentVO.getPayType());
            orderPayment.setPayChannel(paymentVO.getPayChannel());
            platformPayTypes.stream().filter(platformPayType -> platformPayType.getPayType().equals(paymentVO.getPayType()) && platformPayType.getChannels().stream().anyMatch(platformPayChannel -> platformPayChannel.getPayChannel().equals(paymentVO.getPayChannel()))).findFirst().ifPresent(platformPayType -> orderPayment.setFundMode(platformPayType.getFundMode()));
            updatePayments.add(orderPayment);
        }

        orderPaymentRepository.saveAll(updatePayments);

        return Wrapper.success();
    }

    /**
     * 根据订单中的订单总额，修改支付记录中的支付金额
     *
     * @param order 订单
     * @return 修改结果
     */
    @Override
    public Wrapper<Void> vendorUpdatePaymentRate(OrderDO order) {
        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findByOrderAndPayAmountGreaterThan(order, BigDecimal.ZERO, Sort.by("batchNo").ascending());
        if(CollectionUtils.isEmpty(orderPayments)) {
            return Wrapper.success();
        }

        //Step 1: 计算每批次支付的金额
        List<PayNodeBO> payNodes = orderPayments.stream().map(payment -> new PayNodeBO(null , payment.getBatchNo(), payment.getPayNode(), payment.getPayRate())).collect(Collectors.toList());
        Map<Integer, BigDecimal> batchAmount = averagePayNodeAmount(order.getTotalAmount(), payNodes);

        //Step 2: 修改每批次的支付金额
        orderPayments.forEach(payment -> {
            payment.setPayAmount(batchAmount.getOrDefault(payment.getBatchNo(), payment.getPayAmount()));
            //支付金额为0的，设置为完成状态
            if(payment.getPayAmount().compareTo(BigDecimal.ZERO) == 0) {
                payment.setPayTime(LocalDateTime.now());
                payment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_PAY_SUCCESS.getCode());
                payment.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_PAYMENT_CONFIRMED.getCode());
                payment.setOuterStatus(OrderOuterStatusEnum.ACCOMPLISHED.getCode());
            }
        });

        orderPaymentRepository.saveAll(orderPayments);
        return vendorUpdatePaymentRate(order, payNodes);
    }

    /**
     * 根据订单中的订单总额，修改支付记录中的支付金额
     *
     * @param order    订单
     * @param payNodes 支付环节（其中的支付比例要为小数，保留4位数）
     * @return 修改结果
     */
    @Override
    public Wrapper<Void> vendorUpdatePaymentRate(OrderDO order, List<PayNodeBO> payNodes) {
        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findByOrderAndPayAmountGreaterThan(order, BigDecimal.ZERO, Sort.by("batchNo").ascending());
        if(CollectionUtils.isEmpty(orderPayments)) {
            return Wrapper.success();
        }

        if(payNodes.stream().anyMatch(payNode -> orderPayments.stream().noneMatch(payment -> payment.getBatchNo().equals(payNode.getBatchNo())))) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_DOES_NOT_EXIST);
        }

        if(payNodes.stream().map(PayNodeBO::getPayRate).reduce(BigDecimal.ZERO, BigDecimal::add).compareTo(BigDecimal.ONE) != 0) {
            return Wrapper.fail(ResponseCode.ORDER_TRADE_PROCESS_PAYMENT_RATE_SUM_MUST_EQUAL_TO_100);
        }

        //Step 1: 计算每批次支付的金额
        Map<Integer, BigDecimal> batchAmount = averagePayNodeAmount(order.getTotalAmount(), payNodes);

        //Step 2: 修改每批次的支付金额
        orderPayments.forEach(payment -> {
            payNodes.stream().filter(payNode -> payNode.getBatchNo().equals(payment.getBatchNo())).findFirst().ifPresent(payNode -> payment.setPayRate(payNode.getPayRate()));
            payment.setPayAmount(batchAmount.getOrDefault(payment.getBatchNo(), payment.getPayAmount()));
            //如果修改后的支付金额为0，则修改状态为已经完成
            if(payment.getPayAmount().compareTo(BigDecimal.ZERO) == 0 && Objects.isNull(payment.getPayTime())) {
                payment.setPayTime(LocalDateTime.now());
                payment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_PAY_SUCCESS.getCode());
                payment.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_PAYMENT_CONFIRMED.getCode());
                payment.setOuterStatus(OrderOuterStatusEnum.ACCOMPLISHED.getCode());
            }
        });

        orderPaymentRepository.saveAll(orderPayments);
        return Wrapper.success();
    }

    /**
     * （转单）复制交易记录
     *
     * @param order          订单
     * @param payNodes       供应商交易流程设置中的支付环节
     * @param payTypeDetails 上游供应商支付方式列表
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> transferOrderPayments(OrderDO order, List<PayNodeBO> payNodes, List<OrderPayTypeDetailVO> payTypeDetails) {
        //Step 1: 如果不需要支付，返回
        if(CollectionUtils.isEmpty(payNodes)) {
            order.setPayments(new HashSet<>());
            return Wrapper.success();
        }

        //Step 2: 计算每批次支付的金额
        Map<Integer, BigDecimal> batchAmount = averagePayNodeAmount(order.getTotalAmount(), payNodes);

        Integer defaultFundMode = payTypeDetails.get(0).getFundMode();
        Integer defaultPayType = payTypeDetails.get(0).getPayType();
        Integer defaultPayChannel = payTypeDetails.get(0).getPayChannels().get(0).getPayChannel();

        //Step 3: 生成支付记录
        List<OrderPaymentDO> orderPayments = payNodes.stream().map(payNode -> {
            OrderPaymentDO orderPayment = new OrderPaymentDO();
            orderPayment.setOrder(order);
            orderPayment.setPayTime(null);
            orderPayment.setConfirmTime(null);
            orderPayment.setSerialNo(payNode.getSerialNo());
            orderPayment.setBatchNo(payNode.getBatchNo());
            orderPayment.setFundMode(defaultFundMode);
            orderPayment.setPayType(defaultPayType);
            orderPayment.setPayChannel(defaultPayChannel);
            orderPayment.setPayNode(payNode.getPayNode());
            orderPayment.setPayRate(payNode.getPayRate());
            orderPayment.setPayAmount(batchAmount.getOrDefault(payNode.getBatchNo(), BigDecimal.ZERO));
            //支付金额为0的，设置为完成状态
            if(orderPayment.getPayAmount().compareTo(BigDecimal.ZERO) == 0) {
                orderPayment.setPayTime(LocalDateTime.now());
                orderPayment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_PAY_SUCCESS.getCode());
                orderPayment.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_PAYMENT_CONFIRMED.getCode());
                orderPayment.setOuterStatus(OrderOuterStatusEnum.ACCOMPLISHED.getCode());
            } else {
                orderPayment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_TO_PAY.getCode());
                orderPayment.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_TO_CONFIRM_PAYMENT.getCode());
                orderPayment.setOuterStatus(OrderOuterStatusEnum.TO_PAY.getCode());
            }
            orderPayment.setSettlementStatus(OrderPaymentSettlementStatusEnum.NONE.getCode());
            orderPayment.setTradeNo("");
            orderPayment.setRefundNo("");
            orderPayment.setVouchers(new ArrayList<>());
            return orderPayment;
        }).collect(Collectors.toList());

        //保存并设置关联
        orderPaymentRepository.saveAll(orderPayments);
        order.setPayments(new HashSet<>(orderPayments));

        return Wrapper.success();
    }

    /**
     * 修改B2B订单时，查询支付记录
     *
     * @param order 订单
     * @return 查询结果
     */
    @Override
    public List<BuyerOrderPayNodeQueryVO> findBusinessOrderPayments(OrderDO order) {
        return orderPaymentRepository.findByOrderAndPayAmountGreaterThan(order, BigDecimal.ZERO, Sort.by("batchNo").ascending()).stream().map(orderPayment -> {
            BuyerOrderPayNodeQueryVO queryVO = new BuyerOrderPayNodeQueryVO();
            queryVO.setBatchNo(orderPayment.getBatchNo());
            queryVO.setOuterStatusName(OrderOuterStatusEnum.getNameByCode(orderPayment.getOuterStatus()));
            queryVO.setPayAmount(NumberUtil.formatAmount(orderPayment.getPayAmount()));
            queryVO.setPayNode(orderPayment.getPayNode());
            queryVO.setPayType(orderPayment.getPayType());
            queryVO.setPayChannel(orderPayment.getPayChannel());
            queryVO.setPayRate(NumberUtil.formatPayRate(orderPayment.getPayRate()));
            return queryVO;
        }).collect(Collectors.toList());
    }

    /**
     * 平均计算每批次支付的金额
     * @param totalAmount 订单总金额
     * @param payNodes 支付环节设置，支付环节中的支付比例保留4位小数
     * @return 每批次支付的金额
     */
    private Map<Integer, BigDecimal> averagePayNodeAmount(BigDecimal totalAmount, List<PayNodeBO> payNodes) {
        Integer maxBatch = payNodes.stream().map(PayNodeBO::getBatchNo).max(Comparator.comparingInt(Integer::intValue)).orElse(0);
        Map<Integer, BigDecimal> map = payNodes.stream().filter(payNode -> payNode.getBatchNo().compareTo(maxBatch) < 0).collect(Collectors.toMap(PayNodeBO::getBatchNo, payNode -> totalAmount.multiply(payNode.getPayRate()).setScale(2, RoundingMode.HALF_UP)));
        map.put(maxBatch, totalAmount.subtract(map.values().stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO)));
        return map;
    }

    /**
     * 采购商 - 订单支付记录列表
     *
     * @param order 订单
     * @return 支付记录列表
     */
    @Override
    public List<BuyerOrderPaymentDetailVO> findBuyerOrderPayments(OrderDO order) {
        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findByOrderAndPayAmountGreaterThan(order, BigDecimal.ZERO, Sort.by("batchNo").ascending());
        if(CollectionUtils.isEmpty(orderPayments)) {
            return new ArrayList<>();
        }

        //只有最小未支付的次数，才显示“支付”
        Integer batchNo = orderPayments.stream().filter(orderPayment -> orderPayment.getBuyerInnerStatus().equals(BuyerInnerStatusEnum.BUYER_TO_PAY.getCode()) || orderPayment.getBuyerInnerStatus().equals(BuyerInnerStatusEnum.BUYER_PAY_FAIL.getCode()) || (orderPayment.getBuyerInnerStatus().equals(BuyerInnerStatusEnum.BUYER_PAY_SUCCESS.getCode()) && orderPayment.getOuterStatus().equals(OrderOuterStatusEnum.PAYMENT_NOT_ACCOMPLISH.getCode()))).map(OrderPaymentDO::getBatchNo).min(Comparator.comparingInt(Integer::intValue)).orElse(0);
        return orderPayments.stream().map(payment -> {
            BuyerOrderPaymentDetailVO detailVO = new BuyerOrderPaymentDetailVO();
            detailVO.setPaymentId(payment.getId());
            detailVO.setBatchNo(payment.getBatchNo());
            detailVO.setPayType(payment.getPayType());
            detailVO.setPayTypeName(OrderPayTypeEnum.getNameByCode(payment.getPayType()));
            detailVO.setPayChannel(payment.getPayChannel());
            detailVO.setPayChannelName(OrderPayChannelEnum.getNameByCode(payment.getPayChannel()));
            detailVO.setPayNode(payment.getPayNode());
            detailVO.setInnerStatusName(BuyerInnerStatusEnum.getNameByCode(payment.getBuyerInnerStatus()));
            //采购商的外部状态为供应商的内部状态
            detailVO.setOuterStatusName(payment.getOuterStatus().equals(OrderOuterStatusEnum.ACCOMPLISHED.getCode()) ? VendorInnerStatusEnum.getNameByCode(payment.getVendorInnerStatus()) : OrderOuterStatusEnum.getNameByCode(payment.getOuterStatus()));
            detailVO.setPayRate(NumberUtil.formatPayRate(payment.getPayRate()));
            detailVO.setPayAmount(NumberUtil.formatAmount(payment.getPayAmount()));
            detailVO.setVouchers(payment.getVouchers());
            detailVO.setShowPayment(payment.getBatchNo().equals(batchNo));
            return detailVO;
        }).collect(Collectors.toList());
    }

    /**
     * 供应商 - 订单支付记录列表
     *
     * @param order 订单
     * @return 支付记录列表
     */
    @Override
    public List<VendorOrderPaymentDetailVO> findVendorOrderPayments(OrderDO order) {
        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findByOrderAndPayAmountGreaterThan(order, BigDecimal.ZERO, Sort.by("batchNo").ascending());
        if(CollectionUtils.isEmpty(orderPayments)) {
            return new ArrayList<>();
        }

        //只有最小未确认支付结果的次数，才显示“确认支付结果”
        Integer batchNo = orderPayments.stream().filter(orderPayment -> orderPayment.getFundMode().equals(FundModeEnum.DIRECT_TO_ACCOUNT.getCode()) && orderPayment.getVendorInnerStatus().equals(VendorInnerStatusEnum.VENDOR_TO_CONFIRM_PAYMENT.getCode()) && orderPayment.getOuterStatus().equals(OrderOuterStatusEnum.TO_CONFIRM_PAYMENT.getCode())).map(OrderPaymentDO::getBatchNo).min(Comparator.comparingInt(Integer::intValue)).orElse(0);

        return orderPayments.stream().map(payment -> {
            VendorOrderPaymentDetailVO detailVO = new VendorOrderPaymentDetailVO();
            detailVO.setPaymentId(payment.getId());
            detailVO.setBatchNo(payment.getBatchNo());
            detailVO.setPayType(payment.getPayType());
            detailVO.setPayTypeName(OrderPayTypeEnum.getNameByCode(payment.getPayType()));
            detailVO.setPayChannel(payment.getPayChannel());
            detailVO.setPayChannelName(OrderPayChannelEnum.getNameByCode(payment.getPayChannel()));
            detailVO.setPayNode(payment.getPayNode());
            detailVO.setInnerStatusName(VendorInnerStatusEnum.getNameByCode(payment.getVendorInnerStatus()));
            //供应商的外部状态为采购商的内部状态
            detailVO.setOuterStatusName(payment.getOuterStatus().equals(OrderOuterStatusEnum.ACCOMPLISHED.getCode()) ? BuyerInnerStatusEnum.getNameByCode(payment.getBuyerInnerStatus()) : OrderOuterStatusEnum.getNameByCode(payment.getOuterStatus()));
            detailVO.setPayRate(NumberUtil.formatPayRate(payment.getPayRate()));
            detailVO.setPayAmount(NumberUtil.formatAmount(payment.getPayAmount()));
            detailVO.setVouchers(payment.getVouchers());
            detailVO.setShowConfirm(payment.getBatchNo().equals(batchNo));
            detailVO.setShowView(!CollectionUtils.isEmpty(payment.getVouchers()));
            return detailVO;
        }).collect(Collectors.toList());
    }

    /**
     * 平台后台 - 订单支付记录列表
     *
     * @param order 订单
     * @return 支付记录列表
     */
    @Override
    public List<VendorOrderPaymentDetailVO> findPlatformOrderPayments(OrderDO order) {
        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findByOrderAndPayAmountGreaterThan(order, BigDecimal.ZERO, Sort.by("batchNo").ascending());
        if(CollectionUtils.isEmpty(orderPayments)) {
            return new ArrayList<>();
        }

        //只有最小未确认支付结果的次数，才显示“确认支付结果”
        Integer batchNo = orderPayments.stream().filter(orderPayment -> orderPayment.getFundMode().equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()) && orderPayment.getVendorInnerStatus().equals(VendorInnerStatusEnum.VENDOR_TO_CONFIRM_PAYMENT.getCode()) && orderPayment.getOuterStatus().equals(OrderOuterStatusEnum.TO_CONFIRM_PAYMENT.getCode())).map(OrderPaymentDO::getBatchNo).min(Comparator.comparingInt(Integer::intValue)).orElse(0);

        return orderPayments.stream().map(payment -> {
            VendorOrderPaymentDetailVO detailVO = new VendorOrderPaymentDetailVO();
            detailVO.setPaymentId(payment.getId());
            detailVO.setBatchNo(payment.getBatchNo());
            detailVO.setPayType(payment.getPayType());
            detailVO.setPayTypeName(OrderPayTypeEnum.getNameByCode(payment.getPayType()));
            detailVO.setPayChannel(payment.getPayChannel());
            detailVO.setPayChannelName(OrderPayChannelEnum.getNameByCode(payment.getPayChannel()));
            detailVO.setPayNode(payment.getPayNode());
            detailVO.setInnerStatusName(VendorInnerStatusEnum.getNameByCode(payment.getVendorInnerStatus()));
            //供应商的外部状态为采购商的内部状态
            detailVO.setOuterStatusName(payment.getOuterStatus().equals(OrderOuterStatusEnum.ACCOMPLISHED.getCode()) ? BuyerInnerStatusEnum.getNameByCode(payment.getBuyerInnerStatus()) : OrderOuterStatusEnum.getNameByCode(payment.getOuterStatus()));
            detailVO.setPayRate(NumberUtil.formatPayRate(payment.getPayRate()));
            detailVO.setPayAmount(NumberUtil.formatAmount(payment.getPayAmount()));
            detailVO.setVouchers(payment.getVouchers());
            detailVO.setShowConfirm(payment.getBatchNo().equals(batchNo));
            detailVO.setShowView(!CollectionUtils.isEmpty(payment.getVouchers()));
            return detailVO;
        }).collect(Collectors.toList());
    }

    /**
     * 订单创建后，判断、执行支付流程
     *
     * @param order 订单
     * @return 执行结果
     */
    @Override
    public Wrapper<OrderPaymentBO> startOrderPaySerialTasks(OrderDO order) {
        if(CollectionUtils.isEmpty(order.getPayments()) || !order.getTask().getNextPay() || NumberUtil.isNullOrZero(order.getTask().getPayStartNode()) || NumberUtil.isNullOrZero(order.getTask().getPayEndNode())) {
            return Wrapper.success(new OrderPaymentBO());
        }

        //找出支付次数之间的支付记录
        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findByOrderAndBatchNoGreaterThanEqualAndBatchNoLessThanEqual(order, order.getTask().getPayStartNode(), order.getTask().getPayEndNode());
        return completeOrderPaySerialTasks(order, orderPayments);
    }

    /**
     * 订单执行过程中，支付流程执行之前，判断是否跳过支付流程
     *
     * @param order 订单
     * @return 执行结果
     */
    @Override
    public Wrapper<OrderPaymentBO> jumpOverOrderPaySerialTasks(OrderDO order) {
        if(!order.getTask().getNextPay() || NumberUtil.isNullOrZero(order.getTask().getNextSerialNo()) || !StringUtils.hasLength(order.getTask().getTaskId())) {
            return Wrapper.success(new OrderPaymentBO());
        }

        //根据支付批次查询支付记录列表
        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findByOrderAndSerialNo(order, order.getTask().getNextSerialNo());
        return completeOrderPaySerialTasks(order, orderPayments);
    }

    /**
     * 更加支付记录中的支付金额，判断是否执行支付流程
     * @param order  订单
     * @param orderPayments 支付记录列表
     * @return 执行结果
     */
    private Wrapper<OrderPaymentBO> completeOrderPaySerialTasks(OrderDO order, List<OrderPaymentDO> orderPayments) {
        OrderPaymentBO paymentBO = new OrderPaymentBO();
        //如果没有需要支付的记录，返回
        if(CollectionUtils.isEmpty(orderPayments)) {
            return Wrapper.success(paymentBO);
        }

        //Step 1: 如果所有支付记录的金额都为0，跳过支付流程
        if(orderPayments.stream().allMatch(p -> p.getPayAmount().compareTo(BigDecimal.ZERO) == 0)) {
            Wrapper<ProcessTaskBO> taskResult = baseOrderTaskService.execOrderPayTasks(order, 2, Stream.of(OrderServiceContants.AGREE, OrderServiceContants.AGREE).collect(Collectors.toList()));
            if(taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
            }

            return Wrapper.success(paymentBO);
        }

        //Step 2: 找出需要最小支付的次数，返回
        orderPayments.stream().filter(p -> p.getPayAmount().compareTo(BigDecimal.ZERO) > 0).min(Comparator.comparingInt(OrderPaymentDO::getBatchNo)).ifPresent(orderPayment -> {
            paymentBO.setRequirePayment(true);
            paymentBO.setBatchNo(orderPayment.getBatchNo());
            paymentBO.setPayAmount(orderPayment.getPayAmount());
            paymentBO.setPayType(orderPayment.getPayType());
            paymentBO.setPayChannel(orderPayment.getPayChannel());
        });

        return Wrapper.success(paymentBO);
    }

    /**
     * 订单支付后，判断、执行支付流程，调用方要保存 List<OrderDO>
     *
     * @param orders         订单
     * @param orderPaymentList 所有支付记录列表
     * @param batchNo       支付次数
     * @param paySuccess    是否支付成功
     * @param tradeNo       交易订单号
     * @return 执行结果
     */
    @Override
    public Wrapper<Void> execOrderPaySerialTasks(List<OrderDO> orders, List<OrderPaymentDO> orderPaymentList, Integer batchNo, boolean paySuccess, String tradeNo) {
        if(CollectionUtils.isEmpty(orderPaymentList) || orders.stream().anyMatch(order -> !order.getTask().getNextPay() || NumberUtil.isNullOrZero(order.getTask().getPayStartNode()) || NumberUtil.isNullOrZero(order.getTask().getPayEndNode()))) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_DOES_NOT_EXIST);
        }

        //循环每个订单
        for (OrderDO order : orders) {
            //Step 1: 找出订单的支付记录， 支付次数之间的支付记录，与当前的支付记录
            List<OrderPaymentDO> orderPayments = orderPaymentList.stream().filter(payment -> payment.getOrder().getId().equals(order.getId())).collect(Collectors.toList());
            if(CollectionUtils.isEmpty(orderPayments)) {
                return Wrapper.fail(ResponseCode.ORDER_PAYMENT_DOES_NOT_EXIST);
            }

            List<OrderPaymentDO> currentPayments = orderPayments.stream().filter(payment -> payment.getBatchNo().compareTo(order.getTask().getPayStartNode()) >= 0 && payment.getBatchNo().compareTo(order.getTask().getPayEndNode()) <= 0).collect(Collectors.toList());
            if(CollectionUtils.isEmpty(currentPayments)) {
                return Wrapper.fail(ResponseCode.ORDER_PAYMENT_DOES_NOT_EXIST);
            }

            //如果未找到流程定义的支付次数相匹配的支付记录，说明上一次支付处于“支付中”（等待回调通知）的状态
            OrderPaymentDO orderPayment = currentPayments.stream().filter(payment -> payment.getBatchNo().equals(batchNo)).findFirst().orElse(null);
            if(orderPayment == null) {
                return Wrapper.fail(ResponseCode.ORDER_PAYMENT_IS_PROCESSING);
            }

            //Step 2: 修改支付时间，当前支付记录的状态
            orderPayment.setPayTime(LocalDateTime.now());

            //记录交易订单号，用于退款
            if(StringUtils.hasLength(tradeNo)) {
                orderPayment.setTradeNo(tradeNo);
            }

            //如果支付成功，记录“确认到账”时间
            if(paySuccess) {
                orderPayment.setConfirmTime(LocalDateTime.now());
            }

            orderPayment.setBuyerInnerStatus(paySuccess ? BuyerInnerStatusEnum.BUYER_PAY_SUCCESS.getCode() : BuyerInnerStatusEnum.BUYER_PAY_FAIL.getCode());
            orderPayment.setVendorInnerStatus(paySuccess ? VendorInnerStatusEnum.VENDOR_PAYMENT_CONFIRMED.getCode() : VendorInnerStatusEnum.VENDOR_TO_CONFIRM_PAYMENT.getCode());
            orderPayment.setOuterStatus(paySuccess ? OrderOuterStatusEnum.ACCOMPLISHED.getCode() : OrderOuterStatusEnum.TO_PAY.getCode());
            orderPaymentRepository.saveAndFlush(orderPayment);

            //Step 3: 判断流程条件，执行流程
            Wrapper<ProcessTaskBO> taskResult;
            if(paySuccess) {
                if(currentPayments.stream().allMatch(payment -> payment.getOuterStatus().equals(OrderOuterStatusEnum.ACCOMPLISHED.getCode()))) {
                    taskResult = baseOrderTaskService.execOrderPayTasks(order, 2, Stream.of(OrderServiceContants.AGREE, OrderServiceContants.AGREE).collect(Collectors.toList()));
                } else {
                    taskResult = baseOrderTaskService.execOrderPayTasks(order, 2, Stream.of(OrderServiceContants.AGREE, OrderServiceContants.PAY_SERIAL_UNCOMPLETED).collect(Collectors.toList()));
                }
            } else {
                taskResult = baseOrderTaskService.execOrderProcess(order, OrderServiceContants.DISAGREE);
            }

            if(taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
            }

            //Step 4: 判断是否已经成功支付过一次，设置订单支付金额
            order.setPaidAmount(orderPayments.stream().filter(payment -> payment.getPayAmount().compareTo(BigDecimal.ZERO) > 0 && payment.getOuterStatus().equals(OrderOuterStatusEnum.ACCOMPLISHED.getCode())).map(OrderPaymentDO::getPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
            order.setHasPaid(order.getPaidAmount().compareTo(BigDecimal.ZERO) > 0);

            //Step 5: 订单商品加权平均已支付金额
            Wrapper<Void> payAmountResult = baseOrderProductService.updateProductPayAmount(order, order.getPaidAmount());
            if(payAmountResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(payAmountResult.getCode(), payAmountResult.getMessage());
            }
        }

        //Step 6: 缓存支付结果
        if(StringUtils.hasLength(tradeNo)) {
            baseCacheService.cacheOrderPayResult(tradeNo, paySuccess);
        }

        return Wrapper.success();
    }

    /**
     * 采购商，订单支付
     *
     * @param loginUser   用户登录
     * @param orders       订单
     * @param fundMode    资金归集模式
     * @param batchNo     支付次数
     * @param payType     支付方式
     * @param payChannel  支付渠道
     * @param vouchers    支付凭证列表
     * @param payPassword 支付密码
     * @param weChatCode  微信小程序支付时的小程序登录凭证
     * @param returnUrl   支付后的跳转链接
     * @return 支付结果
     */
    @Override
    public Wrapper<OrderPayResultBO> buyerPay(UserLoginCacheDTO loginUser, List<OrderDO> orders, Integer fundMode, Integer batchNo, Integer payType, Integer payChannel, List<String> vouchers, String payPassword, String weChatCode, String returnUrl) {
        //Step 1: 检查参数
        OrderPayTypeEnum orderPayType = OrderPayTypeEnum.parse(payType);
        OrderPayChannelEnum orderPayChannel = OrderPayChannelEnum.parse(payChannel);
        if(orderPayType == null) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_TYPE_MISMATCH);
        }

        if(orderPayChannel == null) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_CHANNEL_MISMATCH);
        }

        if(orderPayType.getPayChannels().stream().noneMatch(channel -> channel.getCode().equals(payChannel))) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_TYPE_AND_PAY_CHANNEL_MISMATCH);
        }

        if(orderPayType.equals(OrderPayTypeEnum.DOES_NOT_NEED) || orderPayChannel.equals(OrderPayChannelEnum.DOES_NOT_NEED)) {
            return Wrapper.success(new OrderPayResultBO());
        }

        // 如果是拆单支付（资金归集模式必须是“平台代收”）
        if(orders.size() > 1 && !fundMode.equals(FundModeEnum.PLATFORM_EXCHANGE.getCode())) {
            return Wrapper.fail(ResponseCode.ORDER_FUND_MODE_MUST_BE_PLATFORM_EXCHANGE);
        }

        //Step 2: 检查采购商是否相同
        if(orders.stream().map(order -> new MemberDTO(order.getBuyerMemberId(), order.getBuyerRoleId())).distinct().count() != 1) {
            return Wrapper.fail(ResponseCode.ORDER_FUND_MODE_MUST_BE_PLATFORM_EXCHANGE);
        }

        //Step 3: 查询支付记录
        List<OrderPaymentDO> orderPaymentList = orderPaymentRepository.findByOrderIn(orders);
        if(CollectionUtils.isEmpty(orderPaymentList)) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_DOES_NOT_EXIST);
        }

        List<OrderPaymentDO> orderPayments = orderPaymentList.stream().filter(payment -> payment.getBatchNo().equals(batchNo)).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(orderPayments) || orderPayments.size() != orders.size()) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_DOES_NOT_EXIST);
        }

        //判断是否正在支付中，或已经支付完成（支付金额为0的支付记录，已经在创建的时候设置为“已完成”状态了）
        if(orderPayments.stream().anyMatch(payment -> payment.getBuyerInnerStatus().equals(BuyerInnerStatusEnum.BUYER_PAYING.getCode()))) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_PROCESSING);
        }

        if(orderPayments.stream().anyMatch(payment -> payment.getOuterStatus().equals(OrderOuterStatusEnum.ACCOMPLISHED.getCode()))) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_HAS_PAID_SUCCESS);
        }

        //支付金额
        BigDecimal payAmount = orderPayments.stream().map(OrderPaymentDO::getPayAmount).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

        //修改支付方式和支付渠道
        orderPayments.forEach(orderPayment -> {
            orderPayment.setFundMode(fundMode);
            orderPayment.setPayType(payType);
            orderPayment.setPayChannel(payChannel);
        });

        // 默认为 “不执行流程”，“支付失败”
        Wrapper<PayChannelResultDTO> payResult = Wrapper.fail(ResponseCode.ORDER_BUSINESS_IS_NOT_COMPLETED);
        //Step 3-2: 根据不同的支付方式、支付渠道，调用不同的接口
        switch (orderPayType) {
            case ONLINE_PAYMENT:
                switch (orderPayChannel) {
                    case ALIPAY:
                        payResult = aliPay(loginUser, orders, orderPayments, fundMode, payAmount);
                        break;
                    case WECHAT_PAY:
                        //根据前端传递的参数中是否包含“微信小程序登录凭证”来判断是小程序支付，还是Native/App支付
                        payResult = StringUtils.hasLength(weChatCode) ? weChatMiniAppPay(loginUser, orders, orderPayments, fundMode, payAmount, weChatCode) : weChatPay(loginUser, orders, orderPayments, fundMode, payAmount);
                        break;
                    case UNION_PAY:
                        break;
                    case ACCOUNT_BALANCE:
                        payResult = balancePay(orders, orderPaymentList, batchNo, payAmount, payPassword, fundMode);
                        break;
                }
                break;
            case OFFLINE_PAYMENT:
                payResult = buyerUpdateVouchers(orders, orderPayments, vouchers);
                break;
            case CREDIT_LINE_PAYMENT:
                payResult = creditPay(orders, orderPaymentList, batchNo, payAmount, fundMode, payPassword);
                break;
            case CASH_ON_DELIVERY:
                payResult = cashOnDeliveryPay(orders, orderPaymentList, batchNo, payAmount, fundMode);
                break;
            case SETTLEMENT:
                payResult = settlementPay(orders, orderPaymentList, batchNo, payAmount, fundMode);
                break;
            case MEMBER_RIGHT:
                payResult = rightPointsPay(orders, orderPaymentList, batchNo, payAmount, payPassword, fundMode);
                break;
            case ALLIN_PAY:
                payResult = allInPay(loginUser, orderPayChannel, orders, orderPayments, fundMode, payAmount, weChatCode);
                break;
            case CCB_PAY:
                switch (orderPayChannel) {
                    case CCB_B2B:
                        payResult = cbcPay(loginUser, orderPayChannel, orders, orderPayments, batchNo, payAmount);
                        break;
                    case CCB_DIGITAL:
                        payResult = cbcDigitalPay(loginUser, orderPayChannel, orders, orderPayments, batchNo, payAmount, returnUrl);
                        break;
                }
                break;
            case COMMERCE_IMPORT_PAY:
                payResult = commerceImportPay(orders, orderPaymentList, batchNo, payAmount, fundMode);
                break;
            default:
                break;
        }

        if(payResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(payResult.getCode(), payResult.getMessage());
        }

        //Step 2: 支付结果
        OrderPayResultBO orderPay = new OrderPayResultBO();
        orderPay.setBatchNo(batchNo);
        orderPay.setPayAmount(payAmount);
        orderPay.setCodeUrl(payResult.getData().getCodeUrl());
        orderPay.setTradeNo(payResult.getData().getTradeNo());

        return Wrapper.success(orderPay);
    }

    /**
     * 微信Native、App支付
     * @param loginUser 登录用户
     * @param orders 订单列表
     * @param orderPayments 订单支付记录列表
     * @param fundMode 资金归集模式
     * @return 二维码链接
     */
    private Wrapper<PayChannelResultDTO> weChatPay(UserLoginCacheDTO loginUser, List<OrderDO> orders, List<OrderPaymentDO> orderPayments, Integer fundMode, BigDecimal payAmount) {
        //Step 1: 支付金额要大于0
        if(payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_AMOUNT_MUST_GT_ZERO);
        }

        //Step 2: 查询支付参数
        Wrapper<OrderPaymentParameterDetailBO> parameterResult = fundMode.equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()) ? baseOrderProcessService.findPlatformPaymentParameters(OrderPayChannelEnum.WECHAT_PAY.getCode()) : baseOrderProcessService.findMemberPaymentParameters(OrderPayChannelEnum.WECHAT_PAY.getCode(), orders.get(0).getVendorMemberId(), orders.get(0).getVendorRoleId());
        if(parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(parameterResult.getCode(), parameterResult.getMessage());
        }

        if(CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
            return Wrapper.fail(fundMode.equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()) ? ResponseCode.ORDER_PLATFORM_PARAMETER_DOES_NOT_EXIST : ResponseCode.ORDER_MEMBER_PARAMETER_DOES_NOT_EXIST);
        }

        String merchantId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String appId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.WECHAT_APP_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String apiKey = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.WECHAT_API_KEY.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        if(!StringUtils.hasLength(merchantId)) {
            return Wrapper.fail(ResponseCode.ORDER_WECHAT_MERCHANT_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(appId)) {
            return Wrapper.fail(ResponseCode.ORDER_WECHAT_APP_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(apiKey)) {
            return Wrapper.fail(ResponseCode.ORDER_WECHAT_API_KEY_IS_MISSING);
        }

        //Step 2: 调用支付服务，微信预支付
        //        由于同一个订单号不能重复支付，（比如生成二维码后不支付，在采购订单中再去支付，微信会报商户订单号重复的错误，所以这里生成一个随机订单号
        //        同时生成一个UUID字符串，作为透传参数，并且作为缓存支付信息的Key，用于在回调时获取支付用户、支付记录等信息
        String tradeNo = orders.size() == 1 ? OrderStringUtil.randomPayOrderNo(orders.get(0).getOrderNo()) : OrderStringUtil.randomPayOrderNo();
        String attach = OrderStringUtil.randomUUID();
        PaymentCacheDTO paymentCache = new PaymentCacheDTO(loginUser, tradeNo, payAmount, orderPayments.stream().map(payment -> new OrderPaymentDTO(payment.getOrder().getId(), payment.getId(), payment.getBatchNo())).collect(Collectors.toList()));

        Wrapper<String> prePayResult = payFeignService.weChatPay(loginUser.getLoginSource(), parameterResult.getData().getMemberId(), parameterResult.getData().getRoleId(), parameterResult.getData().getFundMode(), tradeNo, orders.get(0).getDigest(), payAmount, attach, merchantId, appId, apiKey,orders.get(0).getShopEnvironment());
        if(prePayResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(prePayResult.getCode(), prePayResult.getMessage());
        }

        //Step 4: 缓存支付用户信息，用于回调查询
        baseCacheService.cacheOrderPayment(attach, paymentCache);

        //Step 4: 修改支付记录的支付时间，记录微信商户订单号
        //        注意此时不能更改支付记录的状态，因为生成支付二维码后，用户有可能不支付
        orderPayments.forEach(orderPayment -> {
            orderPayment.setPayTime(LocalDateTime.now());
            orderPayment.setTradeNo(tradeNo);
        });

        orderPaymentRepository.saveAll(orderPayments);
        return Wrapper.success(new PayChannelResultDTO(prePayResult.getData(), tradeNo));
    }

    /**
     * 微信小程序支付
     * @param loginUser 登录用户
     * @param orders 订单列表
     * @param orderPayments 订单支付记录列表
     * @param fundMode 资金归集模式
     * @param weChatCode 小程序登录凭证
     * @return 二维码链接
     */
    private Wrapper<PayChannelResultDTO> weChatMiniAppPay(UserLoginCacheDTO loginUser, List<OrderDO> orders, List<OrderPaymentDO> orderPayments, Integer fundMode, BigDecimal payAmount, String weChatCode) {
        //Step 1: 支付金额要大于0
        if(payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_AMOUNT_MUST_GT_ZERO);
        }

        //Step 2: 查询支付参数
        Wrapper<OrderPaymentParameterDetailBO> parameterResult = fundMode.equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()) ? baseOrderProcessService.findPlatformPaymentParameters(OrderPayChannelEnum.WECHAT_PAY.getCode()) : baseOrderProcessService.findMemberPaymentParameters(OrderPayChannelEnum.WECHAT_PAY.getCode(), orders.get(0).getVendorMemberId(), orders.get(0).getVendorRoleId());
        if(parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(parameterResult.getCode(), parameterResult.getMessage());
        }

        if(CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
            return Wrapper.fail(fundMode.equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()) ? ResponseCode.ORDER_PLATFORM_PARAMETER_DOES_NOT_EXIST : ResponseCode.ORDER_MEMBER_PARAMETER_DOES_NOT_EXIST);
        }

        String merchantId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String apiKey = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.WECHAT_API_KEY.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String appletApiId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.WECHAT_APPLET_APP_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String appletApiKey = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.WECHAT_APPLET_APP_KEY.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        if(!StringUtils.hasLength(merchantId)) {
            return Wrapper.fail(ResponseCode.ORDER_WECHAT_MERCHANT_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(apiKey)) {
            return Wrapper.fail(ResponseCode.ORDER_WECHAT_API_KEY_IS_MISSING);
        }

        if(!StringUtils.hasLength(appletApiId)) {
            return Wrapper.fail(ResponseCode.ORDER_WECHAT_APP_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(appletApiKey)) {
            return Wrapper.fail(ResponseCode.ORDER_WECHAT_APP_KEY_IS_MISSING);
        }

        //Step 2: 调用支付服务，微信预支付
        //        由于同一个订单号不能重复支付，（比如生成二维码后不支付，在采购订单中再去支付，微信会报商户订单号重复的错误，所以这里生成一个随机订单号
        //        同时生成一个UUID字符串，作为透传参数，并且作为缓存支付信息的Key，用于在回调时获取支付用户、支付记录等信息
        String tradeNo = orders.size() == 1 ? OrderStringUtil.randomPayOrderNo(orders.get(0).getOrderNo()) : OrderStringUtil.randomPayOrderNo();
        String attach = OrderStringUtil.randomUUID();
        PaymentCacheDTO paymentCache = new PaymentCacheDTO(loginUser, tradeNo, payAmount, orderPayments.stream().map(payment -> new OrderPaymentDTO(payment.getOrder().getId(), payment.getId(), payment.getBatchNo())).collect(Collectors.toList()));

        Wrapper<String> prePayResult = payFeignService.weChatMiniAppPay(parameterResult.getData().getMemberId(), parameterResult.getData().getRoleId(), parameterResult.getData().getFundMode(), tradeNo, orders.get(0).getDigest(), payAmount, attach, merchantId, apiKey, appletApiId, appletApiKey, weChatCode);
        if(prePayResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(prePayResult.getCode(), prePayResult.getMessage());
        }

        //Step 4: 缓存支付用户信息，用于回调查询
        baseCacheService.cacheOrderPayment(attach, paymentCache);

        //Step 4: 修改支付记录的支付时间，记录微信商户订单号
        //        注意此时不能更改支付记录的状态，因为生成支付二维码后，用户有可能不支付
        orderPayments.forEach(orderPayment -> {
            orderPayment.setPayTime(LocalDateTime.now());
            orderPayment.setTradeNo(tradeNo);
        });

        orderPaymentRepository.saveAll(orderPayments);
        return Wrapper.success(new PayChannelResultDTO(prePayResult.getData(), tradeNo));
    }

    /**
     * 支付宝支付
     * @param loginUser 登录用户
     * @param orders 订单列表
     * @param orderPayments 订单支付记录列表
     * @param fundMode 资金归集模式
     * @return 二维码链接
     */
    private Wrapper<PayChannelResultDTO> aliPay(UserLoginCacheDTO loginUser, List<OrderDO> orders, List<OrderPaymentDO> orderPayments, Integer fundMode, BigDecimal payAmount) {
        //Step 1: 支付金额要大于0
        if(payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_AMOUNT_MUST_GT_ZERO);
        }

        //Step 2: 查询支付参数
        Wrapper<OrderPaymentParameterDetailBO> parameterResult = fundMode.equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()) ? baseOrderProcessService.findPlatformPaymentParameters(OrderPayChannelEnum.ALIPAY.getCode()) : baseOrderProcessService.findMemberPaymentParameters(OrderPayChannelEnum.ALIPAY.getCode(), orders.get(0).getVendorMemberId(), orders.get(0).getVendorRoleId());
        if(parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(parameterResult.getCode(), parameterResult.getMessage());
        }

        if(CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
            return Wrapper.fail(fundMode.equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()) ? ResponseCode.ORDER_PLATFORM_PARAMETER_DOES_NOT_EXIST : ResponseCode.ORDER_MEMBER_PARAMETER_DOES_NOT_EXIST);
        }

        String appId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.ALIPAY_APP_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String publicKey = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.ALIPAY_PUBLIC_KEY.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String privateKey = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.APP_ALIPAY_PRIVATE_KEY.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String appAuthToken = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.ALIPAY_THREAD_APP_AUTH_TOKEN.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");

        if(!StringUtils.hasLength(appId)) {
            return Wrapper.fail(ResponseCode.ORDER_ALIPAY_APP_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(publicKey)) {
            return Wrapper.fail(ResponseCode.ORDER_ALIPAY_PUBLIC_KEY_IS_MISSING);
        }

        if(!StringUtils.hasLength(privateKey)) {
            return Wrapper.fail(ResponseCode.ORDER_ALIPAY_PRIVATE_KEY_MISSING);
        }

        if(fundMode.equals(FundModeEnum.DIRECT_TO_ACCOUNT.getCode()) && !StringUtils.hasLength(appAuthToken)) {
            return Wrapper.fail(ResponseCode.ORDER_ALIPAY_APP_AUTH_TOKEN_IS_MISSING);
        }

        //Step 2: 调用支付服务，支付宝支付
        //        由于同一个订单号不能重复支付，（比如生成二维码后不支付，在采购订单中再去支付，支付宝会报商户订单号重复的错误，所以这里生成一个随机订单号
        //        同时生成一个UUID字符串，作为透传参数，并且作为缓存支付信息的Key，用于在回调时获取支付用户、支付记录等信息
        String tradeNo = orders.size() == 1 ? OrderStringUtil.randomPayOrderNo(orders.get(0).getOrderNo()) : OrderStringUtil.randomPayOrderNo();
        String attach = OrderStringUtil.randomUUID();
        PaymentCacheDTO paymentCache = new PaymentCacheDTO(loginUser, tradeNo, payAmount, orderPayments.stream().map(payment -> new OrderPaymentDTO(payment.getOrder().getId(), payment.getId(), payment.getBatchNo())).collect(Collectors.toList()));

        Wrapper<String> prePayResult = payFeignService.aliPay(loginUser.getLoginSource(), parameterResult.getData().getMemberId(), parameterResult.getData().getRoleId(), parameterResult.getData().getFundMode(), tradeNo, orders.get(0).getDigest(), payAmount, attach, appId, publicKey, privateKey, appAuthToken,orders.get(0).getShopEnvironment());
        if(prePayResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(prePayResult.getCode(), prePayResult.getMessage());
        }

        //Step 4: 缓存支付用户信息，用于回调查询
        baseCacheService.cacheOrderPayment(attach, paymentCache);

        //Step 4: 修改支付记录的支付时间，记录微信商户订单号
        //        注意此时不能更改支付记录的状态，因为生成支付二维码后，用户有可能不支付
        orderPayments.forEach(orderPayment -> {
            orderPayment.setPayTime(LocalDateTime.now());
            orderPayment.setTradeNo(tradeNo);
        });

        orderPaymentRepository.saveAll(orderPayments);
        return Wrapper.success(new PayChannelResultDTO(prePayResult.getData(), tradeNo));
    }

    /**
     * 余额支付
     * @param orders 订单列表
     * @param orderPaymentList 所有支付记录列表
     * @param batchNo 支付次数
     * @param payAmount 支付金额
     * @param payPassword  Aes加密后的支付密码
     * @param fundMode 资金归集模式
     * @return 支付结果
     */
    private Wrapper<PayChannelResultDTO> balancePay(List<OrderDO> orders, List<OrderPaymentDO> orderPaymentList, Integer batchNo, BigDecimal payAmount, String payPassword, Integer fundMode) {
        if(!StringUtils.hasLength(payPassword)) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_PASSWORD_CAN_NOT_BE_EMPTY);
        }

        //Step 1: 支付金额要大于0
        if(payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_AMOUNT_MUST_GT_ZERO);
        }

        //Step 2: 查询支付参数设置
        Wrapper<OrderPaymentParameterDetailBO> parameterResult = fundMode.equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()) ? baseOrderProcessService.findPlatformPaymentParameters(OrderPayChannelEnum.ACCOUNT_BALANCE.getCode()) : baseOrderProcessService.findMemberPaymentParameters(OrderPayChannelEnum.ACCOUNT_BALANCE.getCode(), orders.get(0).getVendorMemberId(), orders.get(0).getVendorRoleId());
        if(parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(parameterResult.getCode(), parameterResult.getMessage());
        }

        //Step 3: 调用支付服务接口进行支付
        String tradeNo = OrderStringUtil.randomPayOrderNo();
        Wrapper<String> payResult = payFeignService.balancePay(orders.get(0).getBuyerMemberId(), orders.get(0).getBuyerRoleId(), parameterResult.getData().getMemberId(), parameterResult.getData().getRoleId(), parameterResult.getData().getFundMode(), tradeNo, payAmount, payPassword);
        if(payResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(payResult.getCode(), payResult.getMessage());
        }

        //Step 4: 支付成功，执行流程
        Wrapper<Void> taskResult = execOrderPaySerialTasks(orders, orderPaymentList, batchNo, true, tradeNo);
        if(taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
        }

        return Wrapper.success(new PayChannelResultDTO(tradeNo));
    }

    /**
     * 积分支付（积分兑换）
     * @param orders 订单列表
     * @param orderPaymentList 所有支付记录列表
     * @param batchNo 支付次数
     * @param payAmount 支付金额
     * @param payPassword  Aes加密后的支付密码
     * @param fundMode 资金归集模式
     * @return 支付结果
     */
    private Wrapper<PayChannelResultDTO> rightPointsPay(List<OrderDO> orders, List<OrderPaymentDO> orderPaymentList, Integer batchNo, BigDecimal payAmount, String payPassword, Integer fundMode) {
        if(!StringUtils.hasLength(payPassword)) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_PASSWORD_CAN_NOT_BE_EMPTY);
        }

        //Step 1: 支付金额要大于0
        if(payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_AMOUNT_MUST_GT_ZERO);
        }

        //Step 2: 调用会员服务接口进行支付
        String tradeNo = orders.size() == 1 ? orders.get(0).getOrderNo() : OrderStringUtil.randomPayOrderNo();
        for (OrderDO order : orders) {
            Wrapper<Void> payResult = memberFeignService.calculateMemberUsedRightPoint(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getVendorMemberId(), order.getVendorRoleId(), fundMode, payPassword, MemberRightSpendTypeEnum.ORDER, payAmount, tradeNo);
            if(payResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(payResult.getCode(), payResult.getMessage());
            }
        }

        //Step 3: 支付成功，执行流程
        Wrapper<Void> taskResult = execOrderPaySerialTasks(orders, orderPaymentList, batchNo, true, tradeNo);
        if(taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
        }

        return Wrapper.success(new PayChannelResultDTO(tradeNo));
    }

    /**
     * 授信额度支付
     * @param orders 订单列表
     * @param orderPaymentList 所有支付记录列表
     * @param batchNo 支付次数
     * @param payAmount 支付金额
     * @param fundMode 资金归集模式
     * @param payPassword （Aes加密后的）支付密码
     * @return 支付结果
     */
    private Wrapper<PayChannelResultDTO> creditPay(List<OrderDO> orders, List<OrderPaymentDO> orderPaymentList, Integer batchNo, BigDecimal payAmount, Integer fundMode, String payPassword) {
        //Step 1: 资金归集模式必须为“会员直接”到账
        if(!fundMode.equals(FundModeEnum.DIRECT_TO_ACCOUNT.getCode())) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_FUND_MODE_MUST_BE_DIRECT_TO_ACCOUNT);
        }

        //判断多订单的供应商是否相同
        List<VendorBO> vendors = orders.stream().map(order -> new VendorBO(order.getVendorMemberId(), order.getVendorRoleId())).distinct().collect(Collectors.toList());
        if(CollectionUtils.isEmpty(vendors) || vendors.size() > 1) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_FUND_MODE_MUST_BE_DIRECT_TO_ACCOUNT);
        }

        //Step 2: 支付金额要大于0
        if(payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_AMOUNT_MUST_GT_ZERO);
        }

        //Step 3: 调用支付服务“授信支付”接口，进行支付
        Wrapper<String> payResult = payFeignService.creditPay(orders.get(0).getBuyerMemberId(), orders.get(0).getBuyerRoleId(), orders.get(0).getVendorMemberId(), orders.get(0).getVendorRoleId(), fundMode, orders.get(0).getOrderNo(), payAmount, payPassword);
        if(payResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(payResult.getCode(), payResult.getMessage());
        }

        //Step 4: 交易号为支付服务返回的交易号。直接将支付记录设置为“支付成功”，执行流程
        String tradeNo = payResult.getData();
        Wrapper<Void> taskResult = execOrderPaySerialTasks(orders, orderPaymentList, batchNo, true, tradeNo);
        if(taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
        }

        return Wrapper.success(new PayChannelResultDTO(tradeNo));
    }

    /**
     * 货到付款支付
     * @param orders 订单列表
     * @param orderPaymentList 所有支付记录列表
     * @param batchNo 支付次数
     * @param payAmount 支付金额
     * @param fundMode 资金归集模式
     * @return 支付结果
     */
    private Wrapper<PayChannelResultDTO> cashOnDeliveryPay(List<OrderDO> orders, List<OrderPaymentDO> orderPaymentList, Integer batchNo, BigDecimal payAmount, Integer fundMode) {
        //货到付款，只需要直接修改状态
        //Step 1: 支付金额要大于0
        if(payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_AMOUNT_MUST_GT_ZERO);
        }

        //Step 2: 直接将支付记录设置为“支付成功”，执行流程
        String tradeNo = orders.size() == 1 ? orders.get(0).getOrderNo() : OrderStringUtil.randomPayOrderNo();
        Wrapper<Void> taskResult = execOrderPaySerialTasks(orders, orderPaymentList, batchNo, true, tradeNo);
        if(taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
        }

        return Wrapper.success(new PayChannelResultDTO(tradeNo));
    }

    /**
     * 账期、月结支付
     * @param orders 订单列表
     * @param orderPaymentList 所有支付记录列表
     * @param batchNo 支付次数
     * @param payAmount 支付金额
     * @param fundMode 资金归集模式
     * @return 支付结果
     */
    private Wrapper<PayChannelResultDTO> settlementPay(List<OrderDO> orders, List<OrderPaymentDO> orderPaymentList, Integer batchNo, BigDecimal payAmount, Integer fundMode) {
        //账期、月结支付，只需要直接修改状态
        //Step 1: 资金归集模式必须为“会员直接”到账
        if(!fundMode.equals(FundModeEnum.DIRECT_TO_ACCOUNT.getCode())) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_FUND_MODE_MUST_BE_DIRECT_TO_ACCOUNT);
        }

        //Step 2: 支付金额要大于0
        if(payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_AMOUNT_MUST_GT_ZERO);
        }

        //Step 3: 直接将支付记录设置为“支付成功”，执行流程
        String tradeNo = orders.size() == 1 ? orders.get(0).getOrderNo() : OrderStringUtil.randomPayOrderNo();
        Wrapper<Void> taskResult = execOrderPaySerialTasks(orders, orderPaymentList, batchNo, true, tradeNo);
        if(taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
        }

        return Wrapper.success(new PayChannelResultDTO(tradeNo));
    }

    /**
     * 通联支付
     * @param loginUser       登录用户
     * @param orderPayChannel 支付渠道
     * @param orders          订单列表
     * @param orderPayments   订单支付记录列表
     * @param fundMode        资金归集模式
     * @param payAmount       支付金额
     * @param weChatCode      小程序登录凭证
     * @return 支付结果
     */
    private Wrapper<PayChannelResultDTO> allInPay(UserLoginCacheDTO loginUser, OrderPayChannelEnum orderPayChannel, List<OrderDO> orders, List<OrderPaymentDO> orderPayments, Integer fundMode, BigDecimal payAmount, String weChatCode) {
        //支付金额要大于0
        if (payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_AMOUNT_MUST_GT_ZERO);
        }

        String tradeNo = orders.size() == 1 ? OrderStringUtil.randomPayOrderNo(orders.get(0).getOrderNo()) : OrderStringUtil.randomPayOrderNo();
        String attach = OrderStringUtil.randomUUID();
        PaymentCacheDTO paymentCache = new PaymentCacheDTO(loginUser, tradeNo, payAmount, orderPayments.stream().map(payment -> new OrderPaymentDTO(payment.getOrder().getId(), payment.getId(), payment.getBatchNo())).collect(Collectors.toList()));

        List<PayAmountDTO> payAmounts = orderPayments.stream().map(payment -> new PayAmountDTO(payment.getOrder().getVendorMemberId(), payment.getOrder().getVendorRoleId(), payment.getPayAmount())).collect(Collectors.toList());
        Wrapper<String> prePayResult = payFeignService.allInPay(loginUser.getLoginSource(), orderPayChannel, loginUser.getMemberId(), loginUser.getMemberRoleId(), fundMode, payAmount, payAmounts, tradeNo, attach, weChatCode);
        if (prePayResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(prePayResult.getCode(), prePayResult.getMessage());
        }

        //缓存支付用户信息，用于回调查询
        baseCacheService.cacheOrderPayment(attach, paymentCache);

        //修改支付记录的支付时间，记录微信商户订单号
        //注意此时不能更改支付记录的状态，因为生成支付二维码后，用户有可能不支付
        for (OrderPaymentDO orderPayment : orderPayments) {
            orderPayment.setPayTime(LocalDateTime.now());
            orderPayment.setTradeNo(tradeNo);
        }

        orderPaymentRepository.saveAll(orderPayments);
        return Wrapper.success(new PayChannelResultDTO(prePayResult.getData(), tradeNo));
    }

    /**
     * 建行B2B支付
     * @param loginUser       登录用户
     * @param orderPayChannel 支付渠道
     * @param orders          订单列表
     * @param orderPayments   订单支付记录列表
     * @param batchNo         支付次数
     * @param payAmount       支付金额
     * @return 支付结果
     */
    private Wrapper<PayChannelResultDTO> cbcPay(UserLoginCacheDTO loginUser, OrderPayChannelEnum orderPayChannel, List<OrderDO> orders, List<OrderPaymentDO> orderPayments, Integer batchNo, BigDecimal payAmount) {
        //支付金额要大于0
        if (payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_AMOUNT_MUST_GT_ZERO);
        }

        //Step 2: 查询支付参数，建行的支付参数在“平台支付参数”中配置
        Wrapper<OrderPaymentParameterDetailBO> parameterResult = baseOrderProcessService.findPlatformPaymentParameters(orderPayChannel.getCode());
        if(parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(parameterResult.getCode(), parameterResult.getMessage());
        }

        if(CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
            return Wrapper.fail(ResponseCode.ORDER_PLATFORM_PARAMETER_DOES_NOT_EXIST);
        }

        String merchantId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_B2B_MERCHANT_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String password = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_B2B_PASSWORD.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String branchId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_B2B_BRANCH_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String posId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_B2B_POS_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String publicKey = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_B2B_PUBLIC_KEY.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String timeoutHours = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_B2B_TIME_OUT_HOURS.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");

        if(!StringUtils.hasLength(merchantId)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_MERCHANT_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(password)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_PASSWORD_IS_MISSING);
        }

        if(!StringUtils.hasLength(branchId)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_BRANCH_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(posId)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_POS_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(publicKey)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_PUBLIC_KEY_IS_MISSING);
        }

        if(!StringUtils.hasLength(timeoutHours)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_TIMEOUT_HOURS_IS_MISSING);
        }

        String tradeNo = orders.size() == 1 ? OrderStringUtil.randomPayOrderNo(orders.get(0).getOrderNo()) : OrderStringUtil.randomPayOrderNo();
        //建行支付订单号不能有“-”
        tradeNo = tradeNo.replaceAll("-", "");
        //建行支付没法在短时间内回调，所以要用消息队列进行接收支付服务的回调通知
        String attach = OrderStringUtil.serializeObject(new OrderPaymentAttachDTO(orderPayChannel.getCode(), orders.stream().map(OrderDO::getId).collect(Collectors.toList()), batchNo,  tradeNo, loginUser.getUserId()));
        Wrapper<String> prePayResult = payFeignService.ccbPay(orders.get(0).getBuyerMemberName(), payAmount, tradeNo, attach, merchantId, password, branchId, posId, publicKey, OrderDateTimeUtil.findDateAfterHours(Long.parseLong(timeoutHours)));
        if (prePayResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(prePayResult.getCode(), prePayResult.getMessage());
        }

        //修改支付记录的支付时间，记录交易订单号
        //注意建行支付这里有一个“支付中的状态
        for (OrderPaymentDO orderPayment : orderPayments) {
            orderPayment.setPayTime(LocalDateTime.now());
            orderPayment.setTradeNo(tradeNo);
            orderPayment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_PAYING.getCode());
        }

        orderPaymentRepository.saveAll(orderPayments);

        //推送至延迟队列，查询订单结果
        OrderPaymentQueueDTO queueDTO = new OrderPaymentQueueDTO();
        queueDTO.setPayChannel(OrderPayChannelEnum.CCB_B2B.getCode());
        queueDTO.setOrderIds(orders.stream().map(OrderDO::getId).collect(Collectors.toList()));
        queueDTO.setBatchNo(batchNo);
        queueDTO.setTradeNo(tradeNo);
        queueDTO.setPaymentIds(orderPayments.stream().map(OrderPaymentDO::getId).collect(Collectors.toList()));
        queueDTO.setUserId(loginUser.getUserId());
        queueDTO.setUserName(loginUser.getUserName());
        queueDTO.setOrganizationName(loginUser.getUserOrgName());
        queueDTO.setJobTitle(loginUser.getUserJobTitle());
        baseOrderScheduleService.scheduleDelayMessage(OrderQueueMessageTypeEnum.PAYMENT_QUERY, queueDTO, Long.parseLong(timeoutHours) * 60 * 60 * 1000);

        return Wrapper.success(new PayChannelResultDTO(prePayResult.getData(), tradeNo));
    }

    /**
     * 查询建行B2B支付结果
     * @param orderPayChannel 支付渠道枚举
     * @param tradeNo 交易号
     * @param orderIds 订单Id列表
     * @param paymentIds 支付记录Id列表
     * @return 查询结果
     */
    private Wrapper<OrderPaymentCallbackStatusEnum> findCbcPayStatus(OrderPayChannelEnum orderPayChannel, String tradeNo, List<Long> orderIds, List<Long> paymentIds) {
        //Step 1: 查询支付参数，建行的支付参数在“平台支付参数”中配置
        Wrapper<OrderPaymentParameterDetailBO> parameterResult = baseOrderProcessService.findPlatformPaymentParameters(orderPayChannel.getCode());
        if(parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(parameterResult.getCode(), parameterResult.getMessage());
        }

        if(CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
            return Wrapper.fail(ResponseCode.ORDER_PLATFORM_PARAMETER_DOES_NOT_EXIST);
        }

        String merchantId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_B2B_MERCHANT_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String password = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_B2B_PASSWORD.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String branchId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_B2B_BRANCH_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String posId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_B2B_POS_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");

        if(!StringUtils.hasLength(merchantId)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_MERCHANT_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(password)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_PASSWORD_IS_MISSING);
        }

        if(!StringUtils.hasLength(branchId)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_BRANCH_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(posId)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_POS_ID_IS_MISSING);
        }

        return payFeignService.queryCcbOrders(tradeNo, merchantId, branchId, posId, password);
    }

    /**
     * 建行数字人民币支付
     * @param loginUser       当前登录用户
     * @param orderPayChannel 支付渠道
     * @param orders          订单列表
     * @param orderPayments   订单支付记录列表
     * @param batchNo         支付次数
     * @param payAmount       支付金额
     * @param returnUrl       支付后跳转链接
     * @return 支付结果
     */
    private Wrapper<PayChannelResultDTO> cbcDigitalPay(UserLoginCacheDTO loginUser, OrderPayChannelEnum orderPayChannel, List<OrderDO> orders, List<OrderPaymentDO> orderPayments, Integer batchNo, BigDecimal payAmount, String returnUrl) {
        //支付金额要大于0
        if (payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_AMOUNT_MUST_GT_ZERO);
        }

        //Step 2: 查询支付参数，建行的支付参数在“平台支付参数”中配置
        Wrapper<OrderPaymentParameterDetailBO> parameterResult = baseOrderProcessService.findPlatformPaymentParameters(orderPayChannel.getCode());
        if(parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(parameterResult.getCode(), parameterResult.getMessage());
        }

        if(CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
            return Wrapper.fail(ResponseCode.ORDER_PLATFORM_PARAMETER_DOES_NOT_EXIST);
        }

        String merchantId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_DIGITAL_MERCHANT_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String branchId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_DIGITAL_BRANCH_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String posId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_DIGITAL_POS_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String publicKey = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_DIGITAL_PUBLIC_KEY.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String timeoutHours = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_DIGITAL_TIME_OUT_HOURS.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        //这两个是非必填参数，不用校验
        String settlementAccount = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_DIGITAL_SETTLEMENT_ACCOUNT.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
        String subMerchantId = parameterResult.getData().getParameters().stream().filter(p -> p.getCode().equals(OrderPaymentParameterEnum.CCB_DIGITAL_SUB_MERCHANT_ID.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");

        if(!StringUtils.hasLength(merchantId)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_MERCHANT_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(branchId)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_BRANCH_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(posId)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_POS_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(publicKey)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_PUBLIC_KEY_IS_MISSING);
        }

        if(!StringUtils.hasLength(timeoutHours)) {
            return Wrapper.fail(ResponseCode.ORDER_CBC_TIMEOUT_HOURS_IS_MISSING);
        }

        String tradeNo = orders.size() == 1 ? OrderStringUtil.randomPayOrderNo(orders.get(0).getOrderNo()) : OrderStringUtil.randomPayOrderNo();
        //建行支付订单号不能有“-”
        tradeNo = tradeNo.replaceAll("-", "");
        //建行支付没法在短时间内回调，所以要用消息队列进行接收支付服务的回调通知
        String attach = OrderStringUtil.serializeObject(new OrderPaymentAttachDTO(orderPayChannel.getCode(), orders.stream().map(OrderDO::getId).collect(Collectors.toList()), batchNo, tradeNo, loginUser.getUserId()));
        //App或小程序支付，在returnUrl之后拼接交易号
        if(loginUser.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_MOBILE.getCode()) && StringUtils.hasLength(returnUrl)) {
            returnUrl = returnUrl.concat("/").concat(tradeNo);
        }

        Wrapper<String> prePayResult = payFeignService.ccbDigitalPay(loginUser.getLoginSource(), orders.get(0).getBuyerMemberName(), payAmount, tradeNo, attach, merchantId, branchId, posId, publicKey, OrderDateTimeUtil.findDateAfterHours(Long.parseLong(timeoutHours)), settlementAccount, subMerchantId, returnUrl);
        if (prePayResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(prePayResult.getCode(), prePayResult.getMessage());
        }

        //修改支付记录的支付时间，记录交易订单号
        //注意建行支付-数字人民币支付没有“支付中的状态
        for (OrderPaymentDO orderPayment : orderPayments) {
            orderPayment.setPayTime(LocalDateTime.now());
            orderPayment.setTradeNo(tradeNo);
        }

        orderPaymentRepository.saveAll(orderPayments);
        return Wrapper.success(new PayChannelResultDTO(prePayResult.getData(), tradeNo));
    }

    /**
     * 跨境电商接口支付
     * @param orders 订单列表
     * @param orderPaymentList 所有支付记录列表
     * @param batchNo 支付次数
     * @param payAmount 支付金额
     * @param fundMode 资金归集模式
     * @return 支付结果
     */
    private Wrapper<PayChannelResultDTO> commerceImportPay(List<OrderDO> orders, List<OrderPaymentDO> orderPaymentList, Integer batchNo, BigDecimal payAmount, Integer fundMode) {
        //支付金额要大于0
        if(payAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_AMOUNT_MUST_GT_ZERO);
        }

        //直接将支付记录设置为“支付成功”，执行流程
        String tradeNo = orders.size() == 1 ? orders.get(0).getOrderNo() : OrderStringUtil.randomPayOrderNo();
        Wrapper<Void> taskResult = execOrderPaySerialTasks(orders, orderPaymentList, batchNo, true, tradeNo);
        if(taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
        }

        return Wrapper.success(new PayChannelResultDTO(tradeNo));
    }

    /**
     * 线下支付 - 支付凭证
     *
     * @param orders 订单列表
     * @param orderPayments 支付记录列表
     * @param vouchers 支付凭证列表
     * @return 更新结果
     */
    private Wrapper<PayChannelResultDTO> buyerUpdateVouchers(List<OrderDO> orders, List<OrderPaymentDO> orderPayments, List<String> vouchers) {
        if(CollectionUtils.isEmpty(vouchers)) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_VOUCHERS_CAN_NOT_BE_EMPTY);
        }

        for (OrderDO order : orders) {
            Wrapper<ProcessTaskBO> taskResult = baseOrderTaskService.execOrderProcess(order, OrderServiceContants.AGREE);
            if(taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
            }
        }

        orderPayments.forEach(orderPayment -> {
            orderPayment.setPayTime(LocalDateTime.now());
            orderPayment.setVouchers(vouchers);
            orderPayment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_PAY_SUCCESS.getCode());
            orderPayment.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_TO_CONFIRM_PAYMENT.getCode());
            orderPayment.setOuterStatus(OrderOuterStatusEnum.TO_CONFIRM_PAYMENT.getCode());
        });

        orderPaymentRepository.saveAll(orderPayments);
        return Wrapper.success(new PayChannelResultDTO());
    }

    /**
     * 查询支付结果
     *
     * @param tradeNo 交易订单号
     * @return 支付结果
     */
    @Override
    public Wrapper<BuyerPayResultDetailVO> findPayResult(String tradeNo) {
        //从Redis中查
        PayResultDTO resultDTO = baseCacheService.findOrderPayResult(tradeNo);
        BuyerPayResultDetailVO detailVO = resultDTO == null ? null : new BuyerPayResultDetailVO(resultDTO.getPaySuccess());
        return Wrapper.success(detailVO);
    }

    /**
     * 订单支付回调，通过OpenFeign接口回调
     *
     * @param orders       订单列表
     * @param paymentCache 支付缓存信息
     * @param paySuccess   是否支付成功
     * @return 支付结果
     */
    @Override
    public Wrapper<Void> buyerPayCallback(List<OrderDO> orders, PaymentCacheDTO paymentCache, Boolean paySuccess) {
        //Step 1: 查询所有支付记录
        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findByOrderIn(orders);
        if(CollectionUtils.isEmpty(orderPayments)) {
            return Wrapper.success();
        }

        //Step 2: 如果有任一条支付次数的状态为“已完成”，返回，避免重复回调
        if(orderPayments.stream().filter(payment -> payment.getBatchNo().equals(paymentCache.getPayments().get(0).getBatchNo())).anyMatch(payment -> payment.getOuterStatus().equals(OrderOuterStatusEnum.ACCOMPLISHED.getCode()))) {
            return Wrapper.success();
        }

        //Step 3: 执行流程
        return execOrderPaySerialTasks(orders, orderPayments, paymentCache.getPayments().get(0).getBatchNo(), paySuccess, paymentCache.getTradeNo());
    }

    /**
     * 订单支付回调，通过消息队列回调
     *
     * @param orderIds         订单Id列表
     * @param batchNo          支付次数
     * @param tradeNo          订单服务生成的支付号
     * @param callbackStatus   支付状态
     * @param userName         用户姓名
     * @param organizationName 用户组织机构名称
     * @param jobTitle         职位
     * @return 支付结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> buyerPayCallback(List<Long> orderIds, Integer batchNo, String tradeNo, OrderPaymentCallbackStatusEnum callbackStatus, String userName, String organizationName, String jobTitle) {
        //Step 1: 查询所有订单
        List<OrderDO> orders = orderRepository.findAllById(orderIds);
        if(CollectionUtils.isEmpty(orders)) {
            return Wrapper.fail(ResponseCode.ORDER_DOES_NOT_EXIST);
        }

        //Step 2: 查询所有支付记录
        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findByOrderIn(orders);
        if(CollectionUtils.isEmpty(orderPayments)) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_DOES_NOT_EXIST);
        }

        //Step 3: 记录采购、供应的上一次内部状态，用于发送报表统计数据
        List<OrderStatusDTO> lastStatus = orders.stream().map(order -> new OrderStatusDTO(order.getId(), order.getBuyerInnerStatus(), order.getVendorInnerStatus())).collect(Collectors.toList());

        //Step 4: 更新订单状态
        // a. 如果是“支付中”，不做任何处理，因为在支付时已经设置为“支付中”了
        // b. 如果是“成功”或“失败”，在流程中进行处理
        boolean paySuccess = false;
        switch (callbackStatus) {
            case PAYING:
                return Wrapper.success();
            case FAILED:
                break;
            case SUCCESS:
                paySuccess = true;
                break;
            default:
                break;
        }

        //Step 3: 执行流程
        Wrapper<Void> result = execOrderPaySerialTasks(orders, orderPayments, batchNo, paySuccess, tradeNo);
        if(result.getCode() != ResponseCode.SUCCESS.getCode()) {
            return result;
        }

        //设置订单完成时间
        orders.stream().filter(v -> OrderOuterStatusEnum.ACCOMPLISHED.getCode().equals(v.getOuterStatus())).forEach(v -> v.setFinishTime(LocalDateTime.now()));

        orderRepository.saveAll(orders);

        boolean finalPaySuccess = paySuccess;
        orders.forEach(order -> {
            String remark = OrderStringEnum.NUMBER_OF_PAYMENTS.getName().concat(String.valueOf(batchNo));
            if(finalPaySuccess) {
                //Step 4-2-a : 订单内、外流转记录 ： 内部记录：支付成功；外部记录：一次支付成功，一次确认到账
                baseOrderHistoryService.saveBuyerInnerHistory(order.getBuyerMemberId(), order.getBuyerRoleId(), userName, organizationName, jobTitle, order.getId(), order.getOrderNo(), OrderOperationEnum.PAY_SUCCESS, order.getBuyerInnerStatus(), remark);
                baseOrderHistoryService.saveBuyerOrderOuterHistory(order.getId(), order.getOrderNo(), order.getBuyerMemberId(), order.getBuyerRoleId(), order.getBuyerMemberName(), OrderServiceContants.SYSTEM_NAME, OrderOperationEnum.CONFIRM_PAYMENT, order.getOuterStatus(), OrderOuterStatusEnum.getNameByCode(order.getOuterStatus()), remark);
            } else {
                //Step 4-2-b : 订单内部流转记录 ： 支付失败
                baseOrderHistoryService.saveBuyerInnerHistory(order.getBuyerMemberId(), order.getBuyerRoleId(), userName, organizationName, jobTitle, order.getId(), order.getOrderNo(), OrderOperationEnum.PAY_FAILED, order.getBuyerInnerStatus(), remark);
            }

            //Step 4-3: 向报表服务发送订单统计数据
            OrderStatusDTO status = lastStatus.stream().filter(s -> s.getOrderId().equals(order.getId())).findFirst().orElse(null);
            baseOrderService.reportBuyerOrder(order.getBuyerMemberId(), order.getBuyerRoleId(), status == null ? 0 : status.getLastBuyerInnerStatus(), order.getBuyerInnerStatus());
            baseOrderService.reportVendorOrder(order.getVendorMemberId(), order.getVendorRoleId(), status == null ? 0 : status.getLastVendorInnerStatus(), order.getVendorInnerStatus());

            //Step 4-4: 向消息服务发送采购商、供应商实时消息
            baseOrderService.messageBuyerOrder(order.getBuyerMemberId(), order.getBuyerRoleId(),order.getBuyerUserId(), order.getBuyerInnerStatus(), order.getOrderNo(), order.getDigest());
            baseOrderService.messageVendorOrder(order.getVendorMemberId(), order.getVendorRoleId(),order.getVendorUserId(), order.getVendorInnerStatus(), order.getOrderNo(), order.getDigest());

            //Step 4-5： 如果是拼团订单，通知营销服务
            baseOrderService.notifyGroupOrder(order);

            //Step 4-5-1: 如果是代发货订单,向营销服务发送优惠券信息
            baseOrderService.sendCoupons(order);

            //Step 4-6 : 订单完成后的操作
            baseOrderService.operateAfterOrderAccomplished(order);
        });

        return Wrapper.success();
    }

    /**
     * 供应商 - 确认支付结果
     *
     * @param order   订单
     * @param batchNo 支付批次
     * @param agree   确认结果，0-确认未支付，1-确认已经支付
     * @return 操作结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> vendorConfirmPayment(OrderDO order, Integer batchNo, Integer agree) {
        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findByOrder(order);
        if(CollectionUtils.isEmpty(orderPayments)) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_DOES_NOT_EXIST);
        }

        List<OrderPaymentDO> currentPayments = orderPayments.stream().filter(payment -> payment.getBatchNo().compareTo(order.getTask().getPayStartNode()) >= 0 && payment.getBatchNo().compareTo(order.getTask().getPayEndNode()) <=0).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(currentPayments)) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_DOES_NOT_EXIST);
        }

        OrderPaymentDO orderPayment = currentPayments.stream().filter(payment -> payment.getBatchNo().equals(batchNo)).findFirst().orElse(null);
        if(orderPayment == null) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_DOES_NOT_EXIST);
        }

        if(orderPayment.getVendorInnerStatus().equals(VendorInnerStatusEnum.VENDOR_PAYMENT_CONFIRMED.getCode())) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_HAS_BEEN_CONFIRMED);
        }

        //Step 1: 更新支付记录的内部状态、外部状态
        // 确认到账：   采购内部状态为“支付成功”， 供应内部状态为“已确认支付结果”， 外部状态为“已完成”
        // 确认未到账： 采购内部状态为“支付成功”， 供应内部状态为“已确认支付结果”， 外部状态为“确认未到账”
        orderPayment.setConfirmTime(agree.equals(OrderServiceContants.AGREE) ? LocalDateTime.now() : null);
        orderPayment.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_PAY_SUCCESS.getCode());
        orderPayment.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_PAYMENT_CONFIRMED.getCode());
        orderPayment.setOuterStatus(agree.equals(OrderServiceContants.AGREE) ? OrderOuterStatusEnum.ACCOMPLISHED.getCode() : OrderOuterStatusEnum.PAYMENT_NOT_ACCOMPLISH.getCode());
        orderPaymentRepository.saveAndFlush(orderPayment);

        //构造返回结果，只需要使用支付的金额
        OrderPaymentBO paymentBO = new OrderPaymentBO();
        paymentBO.setPayAmount(orderPayment.getPayAmount());

        //Step 2: 如果确认到账，且有支付未完成，进行循环，否则执行跳转条件
        Wrapper<ProcessTaskBO> taskResult;
        if(agree.equals(OrderServiceContants.AGREE)) {
            if(currentPayments.stream().allMatch(payment -> payment.getOuterStatus().equals(OrderOuterStatusEnum.ACCOMPLISHED.getCode()))) {
                taskResult = baseOrderTaskService.execOrderProcess(order, OrderServiceContants.AGREE);
            } else {
                taskResult = baseOrderTaskService.execOrderProcess(order, OrderServiceContants.PAY_SERIAL_UNCOMPLETED);
            }
        } else {
            taskResult = baseOrderTaskService.execOrderProcess(order, OrderServiceContants.DISAGREE);
        }

        if(taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
        }

        //Step 4: 判断是否已经成功支付过一次，设置订单支付金额
        order.setPaidAmount(orderPayments.stream().filter(payment -> payment.getPayAmount().compareTo(BigDecimal.ZERO) > 0 && payment.getOuterStatus().equals(OrderOuterStatusEnum.ACCOMPLISHED.getCode())).map(OrderPaymentDO::getPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        order.setHasPaid(order.getPaidAmount().compareTo(BigDecimal.ZERO) > 0);

        //Step 6: 订单商品加权平均已支付金额
        return baseOrderProductService.updateProductPayAmount(order, order.getPaidAmount());
    }

    /**
     * 售后服务 - 退货 - 修改支付次数的金额
     *
     * @param orders        订单列表
     * @param returnAmounts 订单Id及退款金额
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> batchUpdateOrderPayments(List<OrderDO> orders, List<OrderReturnAmountDTO> returnAmounts) {
        if(CollectionUtils.isEmpty(returnAmounts)) {
            return Wrapper.success();
        }

        //查询支付金额大于0，且外部状态为“待支付”和“确认未到账”的支付记录
        List<Integer> outerStatus = Stream.of(OrderOuterStatusEnum.TO_PAY.getCode(), OrderOuterStatusEnum.PAYMENT_NOT_ACCOMPLISH.getCode()).collect(Collectors.toList());
        List<OrderPaymentDO> orderPaymentList = orderPaymentRepository.findByOrderInAndPayAmountGreaterThanAndOuterStatusIn(orders, BigDecimal.ZERO, outerStatus);

        for (OrderReturnAmountDTO returnAmount : returnAmounts) {
            List<OrderPaymentDO> orderPayments = orderPaymentList.stream().filter(payment -> payment.getOrder().getId().equals(returnAmount.getOrderId())).collect(Collectors.toList());
            if(CollectionUtils.isEmpty(orderPayments)) {
                continue;
            }

            //要加上运费
            BigDecimal leftAmount = returnAmount.getLeftAmount().add(orders.stream().filter(order -> order.getId().equals(returnAmount.getOrderId())).map(OrderDO::getFreight).findFirst().orElse(BigDecimal.ZERO));

            Map<Integer, BigDecimal> payAmountMap = averageLeftPayAmount(leftAmount, orderPayments);

            orderPayments.forEach(payment -> payment.setPayAmount(payAmountMap.getOrDefault(payment.getBatchNo(), payment.getPayAmount())));
        }

        orderPaymentRepository.saveAll(orderPaymentList);
        return Wrapper.success();
    }

    /**
     * 拼团订单退款
     *
     * @param order 订单
     * @return 退款结果
     */
    @Override
    public Wrapper<Void> groupOrderRefund(OrderDO order) {
        //Step 1: 退款条件判断
        //Step 1-1: 订单如果不是“拼团失败”，返回
        if(!order.getPromotionStatus().equals(OrderPromotionStatusEnum.GROUP_FAILED.getCode())) {
            return Wrapper.fail(ResponseCode.ORDER_CAN_REFUND_ONLY_WHEN_GROUP_FAILED);
        }

        //Step 1-2: 订单已经全部退款，返回
        if(Objects.nonNull(order.getHasRefund()) && order.getHasRefund()) {
            return Wrapper.fail(ResponseCode.ORDER_HAS_ALREADY_REFUNDED);
        }

        //Step 1-3: 如果订单没有支付过，返回
        if(!order.getHasPaid()) {
            return Wrapper.fail(ResponseCode.ORDER_CAN_NOT_REFUND_WHEN_NOT_PAID);
        }

        //Step 1-4: 如果订单不是一次支付100%金额，返回
        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findByOrder(order);
        if(CollectionUtils.isEmpty(orderPayments)) {
            return Wrapper.fail(ResponseCode.ORDER_PAYMENT_DOES_NOT_EXIST);
        }

        OrderPaymentDO orderPayment = orderPayments.stream().filter(payment -> payment.getPayRate().compareTo(BigDecimal.ONE) == 0 && payment.getOuterStatus().equals(OrderOuterStatusEnum.ACCOMPLISHED.getCode())).findFirst().orElse(null);
        if(orderPayment == null) {
            return Wrapper.fail(ResponseCode.ORDER_CAN_NOT_REFUND_BECAUSE_OF_MANY_PAYMENTS);
        }

        return orderRefund(order, orderPayment, "拼团失败");
    }

    /**
     * 拼团订单退款
     * @param order 订单
     * @param orderPayment 要退款的支付记录
     * @param remark 备注说明
     * @return 退款结果
     */
    @Override
    public Wrapper<Void> orderRefund(OrderDO order, OrderPaymentDO orderPayment, String remark) {
        //Step 2: 支付方式和支付渠道
        OrderPayTypeEnum orderPayType = OrderPayTypeEnum.parse(orderPayment.getPayType());
        OrderPayChannelEnum orderPayChannel = OrderPayChannelEnum.parse(orderPayment.getPayChannel());
        if(orderPayType == null) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_TYPE_MISMATCH);
        }

        if(orderPayChannel == null) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_CHANNEL_MISMATCH);
        }

        //Step 2-1: 根据不同的支付方式、支付渠道，调用不同的接口
        Wrapper<String> refundResult = Wrapper.fail(ResponseCode.ORDER_BUSINESS_IS_NOT_COMPLETED);
        switch (orderPayType) {
            case ONLINE_PAYMENT:
                switch (orderPayChannel) {
                    case ALIPAY:
                        refundResult = aliPayRefund(order, orderPayment);
                        break;
                    case WECHAT_PAY:
                        refundResult = weChatRefund(order, orderPayment);
                        break;
                    case UNION_PAY:
                        break;
                    case ACCOUNT_BALANCE:
                        refundResult = balancePayRefund(orderPayment, remark);
                        break;
                }
                break;
            case OFFLINE_PAYMENT:
                //线下支付方式，直接走售后流程，不需要处理
                return Wrapper.fail(ResponseCode.ORDER_OFFLINE_REFUND_HANDLE_IN_THE_AFTER_SALES_SERVICE);
            case CREDIT_LINE_PAYMENT:
                refundResult = creditPayRefund(order, orderPayment, remark);
                break;
            case CASH_ON_DELIVERY:
                //货到付款方式，直接走售后流程，不需要处理
                return Wrapper.fail(ResponseCode.ORDER_CASH_ON_DELIVERY_REFUND_HANDLE_IN_THE_AFTER_SALES_SERVICE);
            case SETTLEMENT:
                //结算支付方式，直接走售后流程，不需要处理
                return Wrapper.fail(ResponseCode.ORDER_SETTLEMENT_REFUND_HANDLE_IN_THE_AFTER_SALES_SERVICE);
            case MEMBER_RIGHT:
                //积分支付方式，只能换货，不能退款，不需要处理
                return Wrapper.fail(ResponseCode.ORDER_RIGHTS_REFUND_HANDLE_IN_THE_AFTER_SALES_SERVICE);
            case ALLIN_PAY:
                refundResult = allInPayRefund(order, orderPayment);
                break;
            case CCB_PAY:
                switch (orderPayChannel) {
                    case CCB_B2B:
                        refundResult = ccbPayRefund(order, orderPayment);
                        break;
                    case CCB_DIGITAL:
                        refundResult = ccbDigitalPayRefund(order, orderPayment);
                        break;
                }
            default:
                break;
        }

        //如果退款不成功，直接返回
        if(refundResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(refundResult.getCode(), refundResult.getMessage());
        }

        orderPayment.setRefundNo(refundResult.getData());
        order.setHasRefund(true);

        orderPaymentRepository.saveAndFlush(orderPayment);
        orderRepository.saveAndFlush(order);

        return Wrapper.success();
    }

    /**
     * 更新支付记录的结算状态
     *
     * @param paymentIds       支付记录
     * @param settlementStatus 结算状态
     * @return 更新结果
     */
    @Override
    public Wrapper<Void> updatePaymentSettlementStatus(List<Long> paymentIds, Integer settlementStatus) {
        List<OrderPaymentDO> orderPayments = orderPaymentRepository.findAllById(paymentIds);
        orderPayments.forEach(payment -> payment.setSettlementStatus(settlementStatus));
        orderPaymentRepository.saveAll(orderPayments);
        return Wrapper.success();
    }

    /**
     * （调用支付服务接口）查询支付状态
     *
     * @param payChannel 支付渠道
     * @param tradeNo    交易号
     * @param orderIds   订单Id列表
     * @param paymentIds 支付记录列表
     * @return 查询结果
     */
    @Override
    public Wrapper<OrderPaymentCallbackStatusEnum> findPaymentStatus(Integer payChannel, String tradeNo, List<Long> orderIds, List<Long> paymentIds) {
        OrderPayChannelEnum orderPayChannel = OrderPayChannelEnum.parse(payChannel);
        if(orderPayChannel == null) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_CHANNEL_MISMATCH);
        }

        if (orderPayChannel == OrderPayChannelEnum.CCB_B2B) {
            return findCbcPayStatus(orderPayChannel, tradeNo, orderIds, paymentIds);
        }

        return Wrapper.success(OrderPaymentCallbackStatusEnum.PAYING);
    }

    /**
     * 微信退款
     * @param order 订单
     * @param orderPayment 支付记录
     * @return 退款结果
     */
    private Wrapper<String> weChatRefund(OrderDO order, OrderPaymentDO orderPayment) {
        //Step 1: 查询支付参数
        Wrapper<OrderPaymentParameterDetailBO> parameterResult = orderPayment.getFundMode().equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()) ? baseOrderProcessService.findPlatformPaymentParameters(OrderPayChannelEnum.WECHAT_PAY.getCode()) : baseOrderProcessService.findMemberPaymentParameters(OrderPayChannelEnum.WECHAT_PAY.getCode(), order.getVendorMemberId(), order.getVendorRoleId());
        if(parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(parameterResult.getCode(), parameterResult.getMessage());
        }

        if(CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
            return Wrapper.fail(orderPayment.getFundMode().equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()) ? ResponseCode.ORDER_PLATFORM_PARAMETER_DOES_NOT_EXIST : ResponseCode.ORDER_MEMBER_PARAMETER_DOES_NOT_EXIST);
        }

        String merchantId = findPaymentParameter(parameterResult.getData().getParameters(), OrderPaymentParameterEnum.WECHAT_MERCHANT_ID);
        String appId = findPaymentParameter(parameterResult.getData().getParameters(), OrderPaymentParameterEnum.WECHAT_APP_ID);
        String apiKey = findPaymentParameter(parameterResult.getData().getParameters(), OrderPaymentParameterEnum.WECHAT_API_KEY);
        String keyPath = findPaymentParameter(parameterResult.getData().getParameters(), OrderPaymentParameterEnum.WECHAT_KEY_PATH);

        if(!StringUtils.hasLength(merchantId)) {
            return Wrapper.fail(ResponseCode.ORDER_WECHAT_MERCHANT_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(appId)) {
            return Wrapper.fail(ResponseCode.ORDER_WECHAT_APP_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(apiKey)) {
            return Wrapper.fail(ResponseCode.ORDER_WECHAT_API_KEY_IS_MISSING);
        }

        //生成退款单号
        String refundNo = OrderStringUtil.randomUUID();
        Wrapper<Void> refundResult = payFeignService.weChatRefund(order.getVendorMemberId(), order.getVendorRoleId(), orderPayment.getFundMode(), orderPayment.getTradeNo(), orderPayment.getPayAmount(), refundNo, orderPayment.getPayAmount(), merchantId, appId, apiKey, keyPath);
        if(refundResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(refundResult.getCode(), refundResult.getMessage());
        }

        return Wrapper.success(refundNo);
    }

    /**
     * 支付宝退款
     * @param order 订单
     * @param orderPayment 支付记录
     * @return 退款结果
     */
    private Wrapper<String> aliPayRefund(OrderDO order, OrderPaymentDO orderPayment) {
        Wrapper<OrderPaymentParameterDetailBO> parameterResult = orderPayment.getFundMode().equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()) ? baseOrderProcessService.findPlatformPaymentParameters(OrderPayChannelEnum.ALIPAY.getCode()) : baseOrderProcessService.findMemberPaymentParameters(OrderPayChannelEnum.ALIPAY.getCode(), order.getVendorMemberId(), order.getVendorRoleId());
        if(parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(parameterResult.getCode(), parameterResult.getMessage());
        }

        String appId = findPaymentParameter(parameterResult.getData().getParameters(), OrderPaymentParameterEnum.ALIPAY_APP_ID);
        String publicKey = findPaymentParameter(parameterResult.getData().getParameters(), OrderPaymentParameterEnum.ALIPAY_PUBLIC_KEY);
        String privateKey = findPaymentParameter(parameterResult.getData().getParameters(), OrderPaymentParameterEnum.APP_ALIPAY_PRIVATE_KEY);
        String appAuthToken = findPaymentParameter(parameterResult.getData().getParameters(), OrderPaymentParameterEnum.ALIPAY_THREAD_APP_AUTH_TOKEN);
        if(!StringUtils.hasLength(appId)) {
            return Wrapper.fail(ResponseCode.ORDER_ALIPAY_APP_ID_IS_MISSING);
        }

        if(!StringUtils.hasLength(publicKey)) {
            return Wrapper.fail(ResponseCode.ORDER_ALIPAY_PUBLIC_KEY_IS_MISSING);
        }

        if(!StringUtils.hasLength(privateKey)) {
            return Wrapper.fail(ResponseCode.ORDER_ALIPAY_PRIVATE_KEY_MISSING);
        }

        if(orderPayment.getFundMode().equals(FundModeEnum.DIRECT_TO_ACCOUNT.getCode()) && !StringUtils.hasLength(appAuthToken)) {
            return Wrapper.fail(ResponseCode.ORDER_ALIPAY_APP_AUTH_TOKEN_IS_MISSING);
        }

        //生成退款单号
        String refundNo = OrderStringUtil.randomUUID();

        Wrapper<Void> refundResult = payFeignService.aliPayRefund(order.getVendorMemberId(), order.getVendorRoleId(), orderPayment.getFundMode(), orderPayment.getTradeNo(), refundNo, orderPayment.getPayAmount(), appId, publicKey, privateKey, appAuthToken);
        if(refundResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(refundResult.getCode(), refundResult.getMessage());
        }

        return Wrapper.success(refundNo);
    }

    /**
     * 余额支付退款
     * @param orderPayment 支付记录
     * @param remark 备注说明
     * @return 退款结果
     */
    private Wrapper<String> balancePayRefund(OrderPaymentDO orderPayment, String remark) {
        logger.info("余额支付退款开始 => " + orderPayment.getOrder().getId());
        String refundNo = OrderStringUtil.randomUUID();
        Wrapper<Void> refundResult = payFeignService.balancePayRefund(orderPayment.getTradeNo(), orderPayment.getPayAmount(), remark);
        logger.error("余额支付退款结果 => code:" + refundResult.getCode() + " , msg:" + refundResult.getMessage());
        if(refundResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(refundResult.getCode(), refundResult.getMessage());
        }

        return Wrapper.success(refundNo);
    }

    /**
     * 授信支付退款
     * @param order 订单
     * @param orderPayment 支付记录
     * @param remark 备注说明
     * @return 退款结果
     */
    private Wrapper<String> creditPayRefund(OrderDO order, OrderPaymentDO orderPayment, String remark) {
        //Step 1: 资金归集模式必须为“会员直接”到账
        if(!orderPayment.getFundMode().equals(FundModeEnum.DIRECT_TO_ACCOUNT.getCode())) {
            return Wrapper.fail(ResponseCode.ORDER_PAY_FUND_MODE_MUST_BE_DIRECT_TO_ACCOUNT);
        }

        return payFeignService.creditPayRefund(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getVendorMemberId(), order.getVendorRoleId(), orderPayment.getTradeNo(), orderPayment.getPayAmount(), remark);
    }

    /**
     * 通联支付退款
     * @param order 订单
     * @param orderPayment 支付记录
     * @return 退款结果
     */
    private Wrapper<String> allInPayRefund(OrderDO order, OrderPaymentDO orderPayment) {
        //生成退款单号
        String refundNo = OrderStringUtil.randomUUID();
        Wrapper<Void> refundResult = payFeignService.allInPayRefund(order.getBuyerMemberId(), order.getBuyerRoleId(), orderPayment.getFundMode(), orderPayment.getPayAmount(), orderPayment.getTradeNo(), refundNo);
        if(refundResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(refundResult.getCode(), refundResult.getMessage());
        }

        return Wrapper.success(refundNo);
    }

    /**
     * 建行B2B支付退款
     * @param order 订单
     * @param orderPayment 支付记录
     * @return 退款结果
     */
    private Wrapper<String> ccbPayRefund(OrderDO order, OrderPaymentDO orderPayment) {
        //生成退款单号
        String refundNo = OrderStringUtil.randomUUID();
        Wrapper<Void> refundResult = payFeignService.ccbPayRefund(orderPayment.getTradeNo(), refundNo, orderPayment.getPayAmount());
        if(refundResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(refundResult.getCode(), refundResult.getMessage());
        }

        return Wrapper.success(refundNo);
    }

    /**
     * 建行数字人民币支付退款
     * @param order 订单
     * @param orderPayment 支付记录
     * @return 退款结果
     */
    private Wrapper<String> ccbDigitalPayRefund(OrderDO order, OrderPaymentDO orderPayment) {
        //生成退款单号
        String refundNo = OrderStringUtil.randomUUID();
        Wrapper<Void> refundResult = payFeignService.ccbDigitalPayRefund(order.getCreateTime(), orderPayment.getTradeNo(), refundNo, orderPayment.getPayAmount());
        if(refundResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(refundResult.getCode(), refundResult.getMessage());
        }

        return Wrapper.success(refundNo);
    }

    /**
     * 根据支付参数枚举，查找参数
     * @param parameters 平台或会员支付参数设置查询到的支付参数列表
     * @param parameterEnum 支付参数枚举
     * @return 支付参数
     */
    private String findPaymentParameter(List<PayChannelParameterBO> parameters, OrderPaymentParameterEnum parameterEnum) {
        return parameters.stream().filter(p -> p.getCode().equals(parameterEnum.getCode())).map(PayChannelParameterBO::getValue).findFirst().orElse("");
    }

    /**
     * 退货后，计算剩余支付次数的支付金额
     * @param leftAmount （退货后的）商品总额
     * @param orderPayments 支付次数，支付比例保留4位小数
     * @return 每批次支付的金额
     */
    private Map<Integer, BigDecimal> averageLeftPayAmount(BigDecimal leftAmount, List<OrderPaymentDO> orderPayments) {
        if(orderPayments.size() == 1) {
            return orderPayments.stream().collect(Collectors.toMap(OrderPaymentDO::getBatchNo, payment -> leftAmount.multiply(payment.getPayRate()).setScale(2, RoundingMode.HALF_UP)));
        }

        Integer maxBatch = orderPayments.stream().map(OrderPaymentDO::getBatchNo).max(Comparator.comparingInt(Integer::intValue)).orElse(0);
        Map<Integer, BigDecimal> map = orderPayments.stream().filter(payment -> payment.getBatchNo().compareTo(maxBatch) < 0).collect(Collectors.toMap(OrderPaymentDO::getBatchNo, payment -> leftAmount.multiply(payment.getPayRate()).setScale(2, RoundingMode.HALF_UP)));
        map.put(maxBatch, leftAmount.subtract(map.values().stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO)));
        return map;
    }
}
